2.2.7 Transport说明
本节简要介绍 Client-go源码中 Transport包的实现和底层原理。
1. Transport功能说明
Transport提 供 认 证 授 权 安 全 的 传 输 控 制 协 议(TCP,TransmissionControlProtocol)连接,基于 SPDY协议支持 HTTP流(Stream)传输机制。Transport包是通过自定义 Transport对 http.Client的定制化封装实现的,在 Client-go源码中作为工具包为 RESTClient封装 HTTP 客户端请求。在实际开发过程中,一般只需要调用 Client-go中提供的 RESTClient、DiscoveryClient、ClientSet、DynamicClient即可。
2. Transport的内部实现
Transport包主要是对 http.RoundTripper 的封装实现,为了更好地理解本节内容,首先介绍 http.RoundTripper的概念和实现,然后介绍 Transport是怎样封装http.RoundTripper的。最后简要介绍Client-go包中底层的 RESTClient是如何使用 Transport的。
(1) http.RoundTripper
http.RoundTripper能够执行单个 HTTP事务,获取给定请求的响应。实现http.RoundTripper接口的代码通常需要在多个 Goroutine 中并发执行,因此,必须确保实现代码的线程安全性。
http.RoundTripper是在 Go语言 HTTP包中定义的接口,接口定义见代码清单 2-49。
typeRoundTripperinterface{RoundTrip(*Request)(*Response,error)
}
从上述代码中可以看出,http.RoundTripper接口很简单,只定义了一个名为 RoundTrip的方法。RoundTrip() 方法用于执行一个独立的 HTTP事务,接收传入的 *Request 请求值作为参数并返回对应的 *Response响应值,以及一个 error值。任何实现了 RoundTrip() 方法的类型都实现了http.RoundTripper接口。
代码清单 2-50简单展示了 http.RoundTripper接口的实现。
typetestTransportstruct{agentstring
originalTransporthttp.RoundTripper
}
func(c*testTransport)RoundTrip(r*http.Request)(*http.Response,error){iflen(r.Header.Get("User-Agent"))!=0{
returnc.originalTransport.RoundTrip(r)
}
r=utilnet.CloneRequest(r)r.Header.Set("User-Agent",c.agent)
resp,err:=c.originalTransport.RoundTrip(r)
iferr!=nil{
returnnil,err
}
returnresp,nil
}
上述代码定义了一个 testTransport结构体类型,通过实现该类型的RoundTrip方法实现了该类型的 http.RoundTripper接口。该接口的功能是在 HTTP的请求头中添加 User-Agent参数。通过以上 http.RoundTripper接口的简单实现,我们了解了 http.RoundTripper接口是如何封装 HTTP请求的。Transport包中以同样的方式实现了多种封装类型。下面具体介绍 Transport包中 http.RoundTripper的封装。
(2) Transport包中对 http.RoundTripper的封装
Transport包中定义了 New函数,该函数通过传入的 Config参数创建 http.Round-Tripper,具体见代码清单 2-51。
funcNew(config*Config)(http.RoundTripper,error){
//设置Transport的安全级别
ifconfig.Transport!=nil&&(config.HasCA()||config.HasCertAuth()||config.HasCertCallback()||config.TLS.Insecure){
returnnil,fmt.Errorf("usingacustomtransportwithTLScertificateoptionsortheinsecureflagisnotallowed")
}
var(
rthttp.RoundTrippererrerror
)
ifconfig.Transport!=nil{rt=config.Transport
}else{
rt,err=tlsCache.get(config)
iferr!=nil{returnnil,err
}
}
returnHTTPWrappersForConfig(config,rt)
}
在 New函数中,首先通过 config 对象的方法获取认证信息,如果认证信息是非安全设置的,则返回 nil;如果配置中满足安全设置,则 New函数会读取配置中的 Transport信息;如果 Transport为空,New 函数就从缓存中读取缓存的 Transport,如果缓存中没有Transport,那么需要初始化一个默认的 Transport。最后调用 HTTPWrappersForConfig函数,该函数将Config作为参数对 Transport进行进一步的封装。
HTTPWrappersForConfig函数见代码清单 2-52。
funcHTTPWrappersForConfig(config*Config,rthttp.RoundTripper)(http.RoundTripper,
error){
ifconfig.WrapTransport!=nil{rt=config.WrapTransport(rt)
}
rt=DebugWrappers(rt)
//Setauthenticationwrappersswitch{
caseconfig.HasBasicAuth()&&config.HasTokenAuth():
returnnil,fmt.Errorf("username/passwordorbearertokenmaybeset,butnot
both")
caseconfig.HasTokenAuth():
varerrerror
rt,err=NewBearerAuthWithRefreshRoundTripper(config.BearerToken,config.
BearerTokenFile,rt)
iferr!=nil{returnnil,err
}
caseconfig.HasBasicAuth():
rt=NewBasicAuthRoundTripper(config.Username,config.Password,rt)
}
iflen(config.UserAgent)>0{
rt=NewUserAgentRoundTripper(config.UserAgent,rt)
}
iflen(config.Impersonate.UserName)>0||len(config.Impersonate.Groups)>0||len(config.Impersonate.Extra)>0{
rt=NewImpersonatingRoundTripper(config.Impersonate,rt)
}
returnrt,nil
}
HTTPWrappersForConfig函数可以根据不同配置的认证信息创建不同的 http.Round‐Tripper。由以上代码可知该函数共创建了4种不同类型的 http.RoundTripper。
① NewBearerAuthWithRefreshRoundTripper创建了 BearerAuthWithRefres-hRoundTripper类型对象, 实现了 http.RoundTripper接口, 并将提供的Bearer令牌添加到请求中,如果 tokenFile是非空的,则定期读取 tokenFile,最后一次成功读取的内容作为 Bearer令牌;如果 tokenFile是非空的,而 Bearer是空的,tokenFile会被立即读取,以填充初始的 Bearer 令牌。
② NewBasicAuthRoundTripper创建了 basicAuthRoundTripper类型对象,它将基本 auth 授权应用到请求中,通过用户名和密码授权实现 http.RoundTripper接口。
③ NewUserAgentRoundTripper创建了userAgentRoundTripper类型对象,它向请求添加 User-Agent请求头,实现了 http.RoundTripper接口。
④ NewImpersonatingRoundTripper创建了 ImpersonatingRoundTripper类型对象,向请求添加一个 Act-As请求头,实现了 http.RoundTripper接口。
以上4种不同类型的http.RoundTripper实现方式与2.2.6 节的案例实现是同一种方式,这里不再赘述。除了以上4种不同类型的 http.RoundTripper对 http.RoundTripper接口的实现,Transport中还包括 authProxyRoundTripper、debuggingRoundTripper等其他类型,具体可在/client-go/transport/round_trippers.go文件中查看。