带你读《云原生应用开发 Operator原理与实践》第二章 Operator 原理2.2Client-go 原理(十四)

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文件中查看。

上一篇:微信开放平台开发——网页微信扫码登录(OAuth2.0)


下一篇:多多客微信百度支付宝三端合一小程序平台正式上线,集齐BAT,开启新篇章!