改变* http.Client传输

时间:2017-04-17 07:48:44

标签: go

现状

选择了一个侧面项目(围绕第三方API构建包装器),我被困住了。我正在使用sling撰写我的HTTP请求。

因此,客户的部分内容如下:

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)
}

//....

我无法解决的问题

我遵循与go-githubgo-twitter相同的原则,我的库不应该处理身份验证,而是使用golangs oauth1 / 2包。

由于API提供应用程序和用户级别身份验证,而某些工作流程需要初始应用程序级别身份验证,然后需要用户级别身份验证,我的问题是,如果有任何方法可以更改*http.Transport以便更改基于客户端的身份验证标头。

到目前为止,我还没有找到办法。

1 个答案:

答案 0 :(得分:4)

http.Client有一个Transport字段,您可以使用该字段“根据客户端更改身份验证标头”,如果这是您想要的。 Transport字段的类型为http.RoundTripper,这是一个方法接口,因此您需要做的就是使用RoundTrip方法的实现来定义传输。

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)
}

现在,您可以使用此类型的实例在Transport上设置http.Client字段。

var client *http.Client = // get client from somewhere...
// set the transport to your type
client.Transport = &MyTransport{apiKey: "secret", tr: client.Transport}

根据您获取客户端的方式和位置,可能尚未设置其Transport字段,因此在这种情况下确保您的类型使用默认传输可能是个好主意。

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)
}

值得注意的是,Go documentation建议不要修改*http.Request方法中的RoundTrip,以便您可以执行的操作以及go-github打包的内容链接到正在做的,是创建请求的副本,在其上设置auth标头,并将其传递给基础Transport。见这里:https://github.com/google/go-github/blob/master/github/github.go#L841-L875