更改 *http.Client 传输

Den*_*ner 4 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)
}

//....
Run Code Online (Sandbox Code Playgroud)

我无法理解的事情

我遵循与go-github和go-twitter相同的原则,即身份验证不应由我的库处理,而应由 golangs oauth1/2 包处理。

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

到目前为止,我还没有找到这样做的方法。

mko*_*iva 11

如果这是您想要的,它http.Client有一个Transport字段,您可以使用它来“根据客户端更改身份验证标头”。该Transport字段的 typehttp.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)
}
Run Code Online (Sandbox Code Playgroud)

现在您可以使用这种类型的实例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}
Run Code Online (Sandbox Code Playgroud)

根据您获得客户端的方式和地点,它的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)
}
Run Code Online (Sandbox Code Playgroud)

可能值得注意的是,Go 文档建议不要修改方法*http.Request内部RoundTrip,所以你可以做的,以及你链接到的go-github包正在做什么,是创建请求的副本,设置 auth 标头在它上面,并将其传递给底层Transport. 见这里:https : //github.com/google/go-github/blob/d23570d44313ca73dbcaadec71fc43eca4d29f8b/github/github.go#L841-L875