使用客户端为每个HTTP请求添加标头

时间:2019-01-08 09:20:22

标签: go http-headers go-http

我知道我可以使用

手动将标头添加到每个HTTP请求中
cli := &http.Client{}
req, err := http.NewRequest("GET", "https://myhost", nil)
req.Header.Add("X-Test", "true")
if err != nil {
    panic(err)
}
rsp, err := cli.Do(req)

但是我想为我的应用程序中的每个HTTP请求自动添加此标头。

最好的方法是什么?

2 个答案:

答案 0 :(得分:3)

我知道三种可能的解决方案。按照我的优先顺序:

  1. 用自定义代码包装http.NewRequest,以添加所需的标题:

    func MyRequest(method, path url, body io.Reader) (*http.Request, error) {
        req, err := http.NewRequest(method, path, body)
        if err != nil {
            return nil, err
        }
        req.Header.Add("X-Test", "true")
        return req, nil
    }
    

    这种方法的优点是直截了当,非魔术性和可移植性。它可以与添加了自己的标头或设置自定义传输方式的任何第三方软件一起使用。

    唯一不起作用的情况是,您依赖第三方库来创建HTTP请求。我希望这种情况很少见(以我自己的经历,我不会记得碰到过这种情况)。即使在这种情况下,也许您也可以包装那个调用。

  2. 包装对client.Do的调用以添加标头,并可能添加任何其他共享逻辑。

    func MyDo(client *http.Client, req *http.Request) (*http.Response, error) {
        req.Header.Add("X-Test", "true")
        // Any other common handling of the request
        res, err := client.Do(req)
        if err != nil {
            return nil, err
        }
        // Any common handling of response
        return res, nil
    }
    

    这种方法也是简单明了的,并且具有易于减少其他样板的附加优势(超过#1)。与#1结合使用时,这种通用方法也可以很好地工作。一种可能的缺点是您必须始终直接调用MyDo方法,这意味着您不能依赖于调用http.Do本身的第三方软件。

  3. 使用自定义http.Transport

    type myTransport struct{}
    
    func (t *myTransport) RoundTrip(req *http.Request) (*http.Response, error) {
        req.Header.Add("X-Test", "true")
        return http.DefaultTransport.RoundTrip(req)
    }
    

    然后像这样使用它:

    client := &Client{Transport: &myTransport{}}
    req := http.NewRequest("GET", "/foo", nil)
    res, err := client.Do(req)
    

    这种方法的优点是几乎可以与任何其他软件一起在“幕后”工作,因此,如果您依赖第三方库来创建http.Request对象并调用http.Do ,这可能是您唯一的选择。

    但是,这具有潜在的缺点,即不明显,如果您使用的任何第三方软件也设置了自定义传输,则可能会损坏(不必费心遵守现有的自定义传输)。

最终,您使用哪种方法取决于您需要使用第三方软件的哪种类型的可移植性。但是,如果不必担心,我建议使用最明显的解决方案,据我估计,这是上面提供的顺序。

答案 1 :(得分:1)

可以将http.Client配置为使用自定义传输,该传输可以处理客户端中的每个请求(在golang.org/x/oauth2库中找到此实现)。此示例将标头附加到每个http请求:

type transport struct {
    headers map[string]string
    base    http.RoundTripper
}

func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
    for k, v := range t.headers {
        req.Header.Add(k, v)
    }
    base := t.base
    if base == nil {
        base = http.DefaultTransport
    }
    return base.RoundTrip(req)
}

func main() {
    cli := &http.Client{
        Transport: &transport{
            headers: map[string]string{
                "X-Test": "true",
            },
        },
    }
    rsp, err := cli.Get("http://localhost:8080")
    defer rsp.Body.Close()
    if err != nil {
        panic(err)
    }
}