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)
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檔案中檢視。