http.Transport
是Go语言net/http
包中的一个重要结构体,它实现了http.RoundTripper
接口,用于管理HTTP和HTTPS请求的发送。在Go的HTTP客户端实现中,http.Transport
是底层的传输实现,它负责管理TCP连接、处理TLS握手、支持HTTP/2、复用连接以及管理空闲连接等。
http.Transport的主要字段
http.Transport
的主要字段包括:
-
Proxy
:定义了一个函数,该函数接收一个http.Request
对象,返回一个代理服务器的URL。如果该字段为nil,http.Transport
会使用环境变量(HTTP_PROXY、HTTPS_PROXY、NO_PROXY)来找到代理服务器。 -
DialContext
:定义了一个函数,该函数接收一个context.Context
对象和一个表示网络类型和地址的字符串,返回一个net.Conn
对象。如果该字段为nil,http.Transport
会使用默认的拨号器。 -
MaxIdleConns
:限制了持久连接的最大空闲连接数。如果该字段为0,http.Transport
不会限制空闲连接数。 -
IdleConnTimeout
:限制了空闲连接在连接池中的最大存活时间。如果该字段为0,http.Transport
不会限制空闲连接的存活时间。 -
TLSHandshakeTimeout
:限制了TLS握手的最大等待时间。如果该字段为0,http.Transport
会使用默认的TLS握手超时时间。
http.Transport的工作原理
当你使用http.Client
发送请求时,这个请求会通过http.Transport
发送。http.Transport
首先会查看是否有可复用的空闲连接。如果有,它会复用这个连接发送请求;如果没有,它会创建一个新的连接。
创建新连接的过程包括拨号、进行TLS握手(如果需要的话)以及发送HTTP请求。在发送HTTP请求时,http.Transport
会添加必要的请求头,例如Host、User-Agent和Accept-Encoding。
在接收到HTTP响应后,http.Transport
会读取响应头,然后返回一个http.Response
对象。这个对象的Body字段是一个io.ReadCloser
,你可以从中读取响应的主体内容。
在你读取完响应主体并关闭http.Response.Body
后,如果这个连接是持久的(即服务器没有发送Connection: close
头),http.Transport
会将这个连接放回连接池,以便复用。
http.Transport的连接复用
在 Go 的 http
包中,连接复用是通过 http.Transport
结构体来实现的。当你使用 http.Client
发送请求时,如果服务器支持持久连接(也就是 HTTP/1.1 的 keep-alive),那么 http.Transport
会复用这个连接进行多次请求,而不是每次请求都重新建立连接。
具体来说,http.Transport
会维护一个空闲连接池,当一个请求结束后,如果这个连接还可以复用(比如服务器没有关闭连接,没有达到连接的空闲超时时间等),那么这个连接就会被放回连接池。当有新的请求到来时,http.Transport
会首先查看连接池中是否有可用的连接,如果有,就直接复用这个连接,如果没有,就新建一个连接。
这个过程主要是在 http.Transport
的 getConn
方法中实现的。这个方法会首先查看空闲连接池,如果有可用的连接,就直接复用;如果没有,就会创建一个新的连接。创建新连接的过程在 dialConn
方法中实现。
在 http.Transport
的 roundTrip
方法中,会调用 getConn
方法获取连接,然后使用这个连接发送请求。请求结束后,如果连接还可以复用,就会调用 putOrCloseIdleConn
方法将连接放回连接池。
自定义http.Transport
你可以创建一个自定义的http.Transport
,以便更细粒度地控制HTTP请求的发送。例如,你可以设置代理服务器、修改拨号函数、限制空闲连接数和存活时间等。
下面是一个创建自定义http.Transport
的例子:
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
client := &http.Client{Transport: tr}
resp, err := client.Get("http://example.com")
在这个例子中,我们创建了一个自定义的http.Transport
,并将其设置为http.Client
的Transport字段。这样,当我们使用client.Get
发送请求时,请求就会通过我们自定义的http.Transport
发送。
总的来说,http.Transport
是Go语言HTTP客户端的核心组件,它提供了丰富的字段和方法,让我们可以灵活地控制HTTP请求的发送。理解http.Transport
的工作原理和用法,对于编写高效的HTTP客户端代码非常重要。