英文:
Change *http.Client transport
问题
现状
我选择了一个边项目(构建第三方API的包装器),但卡住了。我正在使用sling来组合我的HTTP请求。
所以客户端的部分如下所示:
type Client struct {
// 一些服务等...
sling *sling.Sling <-- 这是用*http.Client初始化的
}
func NewClient(httpClient *http.Client) *Client {
sling := sling.New().Client(httpClient).Base(BaseURL)
}
//....
我无法理解的事情
我遵循与go-github和go-twitter相同的原则,即认证不应由我的库处理,而应由golang的oauth1/2包处理。
由于API提供应用程序级和用户级认证,并且某些工作流程需要初始的应用程序级认证,然后是用户级认证,我的问题是,是否有任何方法可以更改*http.Transport
以便在客户端基础上更改身份验证标头。
到目前为止,我还没有找到方法来实现这一点。
英文:
The Status Quo
Having picked a side project (building a wrapper around a third party API), I'm stuck. I am using sling to compose my HTTP requests.
So parts of the Client are composed as follows:
type Client struct {
// some services etc..
sling *sling.Sling <-- this is initialized with *http.Client
}
func NewClient(httpClient *http.Client) *Client {
sling := sling.New().Client(httpClient).Base(BaseURL)
}
//....
Things I can't wrap my head around
I am following the same principle as go-github and go-twitter that authentication should not be handled by my library, but rather by golangs oauth1/2 package.
As the the API provides application and user level authentication and some of the workflows require initial application level authentication and then user level authentication, my question is, if there is any way to change the *http.Transport
in order to change the authentication header on a client basis.
So far, I haven't found a way to do so.
答案1
得分: 13
http.Client
有一个Transport
字段,你可以使用它来"在客户端基础上更改身份验证标头",如果这是你想要的。Transport
字段的类型是http.RoundTripper
,它是一个只有一个方法的接口,所以你只需要定义一个实现RoundTrip
方法的传输。
type MyTransport struct {
apiKey string
// 保留对客户端原始传输的引用
rt http.RoundTripper
}
func (t *MyTransport) RoundTrip(r *http.Request) (*http.Response, error) {
// 在这里设置你的身份验证标头
r.Header.Set("Auth", t.apiKey)
return t.rt.RoundTrip(r)
}
现在,你可以使用这个类型的实例来设置http.Client
的Transport
字段。
var client *http.Client = // 从某个地方获取客户端...
// 将传输设置为你的类型
client.Transport = &MyTransport{apiKey: "secret", rt: client.Transport}
根据你获取客户端的方式和位置,可能客户端的Transport
字段尚未设置,所以在这种情况下,确保你的类型使用默认传输可能是一个好主意。
func (t *MyTransport) transport() http.RoundTripper {
if t.rt != nil {
return t.rt
}
return http.DefaultTransport
}
// 根据需要更新你的方法
func (t *MyTransport) RoundTrip(r *http.Request) (*http.Response, error) {
// 在这里设置你的身份验证标头
r.Header.Set("Auth", t.apiKey)
return t.transport().RoundTrip(r)
}
值得注意的是,Go文档建议不要在RoundTrip
方法内修改*http.Request
,所以你可以做的,以及你提供的go-github包正在做的,是创建一个请求的副本,在副本上设置身份验证标头,并将其传递给底层的Transport
。参见这里:https://github.com/google/go-github/blob/d23570d44313ca73dbcaadec71fc43eca4d29f8b/github/github.go#L841-L875
英文:
The http.Client
has a Transport
field that you could use to "change the authentication header on a client basis" if that's what you want. The Transport
field has type http.RoundTripper
which is a one method interface, so all you need to do is to define your transport with an implementation of the RoundTrip
method.
type MyTransport struct {
apiKey string
// keep a reference to the client's original transport
rt http.RoundTripper
}
func (t *MyTransport) RoundTrip(r *http.Request) (*http.Response, error) {
// set your auth headers here
r.Header.Set("Auth", t.apiKey)
return t.rt.RoundTrip(r)
}
Now you can use an instance of this type to set the Transport
field on an http.Client
.
var client *http.Client = // get client from somewhere...
// set the transport to your type
client.Transport = &MyTransport{apiKey: "secret", tr: client.Transport}
Depending on how and where from you got the client, it's possible that its Transport
field is not yet set, so it might be a good idea to ensure that your type uses the default transport in such a case.
func (t *MyTransport) transport() http.RoundTripper {
if t.rt != nil {
return t.rt
}
return http.DefaultTransport
}
// update your method accordingly
func (t *MyTransport) RoundTrip(r *http.Request) (*http.Response, error) {
// set your auth headers here
r.Header.Set("Auth", t.apiKey)
return t.transport().RoundTrip(r)
}
It might be worth noting that the Go documentation recommends not to modify the *http.Request
inside the RoundTrip
method, so what you can do, and what the go-github package you linked to is doing, is to create a copy of the request, set the auth headers on it, and pass that to the underlying Transport
. See here: https://github.com/google/go-github/blob/d23570d44313ca73dbcaadec71fc43eca4d29f8b/github/github.go#L841-L875
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论