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

Kir*_*ill 4 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)
Run Code Online (Sandbox Code Playgroud)

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

最好的方法是什么?

Fli*_*mzy 9

我知道三个可能的解决方案。在(我的)优先顺序中:

  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
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这种方法的优点是直接、非魔法和便携。它将与任何第三方软件一起使用,添加自己的标头或设置自定义传输。

    唯一不起作用的情况是,如果您依赖第三方库来创建 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
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这种方法也很简单,并且具有额外的优势(超过 #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)
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后像这样使用它:

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

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

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

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