返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

client

发布于 2024-10-12 19:15:53 字数 2756 浏览 0 评论 0 收藏 0

客户端对应 HTTP 请求的方法实现。

  • 并发安全。如果要复用连接,应该使用单一实例。
  • 或直接用 DefaultClient 提供的便捷函数。
  • 必须调用 resp.Body.Close
func main() {
	resp, _ := http.Get("http://localhost:8080/hello")
	defer resp.Body.Close()

	b, _ := io.ReadAll(resp.Body)
	fmt.Println(string(b))
}

源码剖析

最关键的装置是 Transport ,执行请求并返回结果。与服务器端 Handler 接口相呼应。

// http/client.go

type Client struct {
    
	// Transport specifies the mechanism by which individual
	// HTTP requests are made. If nil, DefaultTransport is used.
	Transport RoundTripper
}

标准库内有三种实现,默认是 Transport ,它还负责缓存连接以供复用。

type RoundTripper interface {
	RoundTrip(*Request) (*Response, error)
}
                       +----------------+
                       |  RoundTripper  |
                       +----------------+
                                |
           +--------------------+--------------------+
           |                    |                    |
    +-------------+     +----------------+   +---------------+
    |  Transport  |     | http2Transport |   | fileTransport |
    +-------------+     +----------------+   +---------------+
    

从头开始梳理执行过程。

// http/client.go

func (c *Client) Get(url string) (resp *Response, err error) {
	req, err := NewRequest("GET", url, nil)
	return c.Do(req)
}

func (c *Client) Do(req *Request) (*Response, error) {
	return c.do(req)
}
// http/client.go

func (c *Client) do(req *Request) (retres *Response, reterr error) {
    
	resp, didTimeout, err = c.send(req, deadline)

	if !shouldRedirect {
        return resp, nil
	}
}
// http/client.go

func (c *Client) send(req *Request, deadline time.Time) (...) {
	resp, didTimeout, err = send(req, c.transport(), deadline)
}

func send(ireq *Request, rt RoundTripper, deadline time.Time) (...) {
    resp, err = rt.RoundTrip(req)
}

默认使用 DefaultTransport ,支持 HTTP、HTTPS 和代理。
设置 Transport.DisableKeepAlivesRequest.Close 阻止缓存连接。

// http/client.go

func (c *Client) transport() RoundTripper {
	if c.Transport != nil {
		return c.Transport
	}
	return DefaultTransport
}
// http/transport.go

// roundTrip implements a RoundTripper over HTTP.
func (t *Transport) roundTrip(req *Request) (*Response, error) {
	for {
		treq := &transportRequest{Request: req, ... cancelKey: cancelKey}
        
        // 使用当前请求信息,构建 map 主键。
		cm, err := t.connectMethodForRequest(treq)

        // 获取网络连接。(复用或新建)
		pconn, err := t.getConn(treq, cm)

        // 返回。
		resp, err = pconn.roundTrip(treq)
		if err == nil {
			resp.Request = origReq
			return resp, nil
		}
	}
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文