使用客户端为每个 HTTP 请求添加 headers
Add headers for each HTTP request using client
我知道我可以使用
向每个 HTTP 请求手动添加 headers
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 请求自动添加此 header。
最好的方法是什么?
可以配置 http.Client
以使用自定义传输,它可以处理客户端中的每个请求(在 golang.org/x/oauth2 库中找到此实现)。此示例将 headers 附加到每个 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)
}
}
我知道三种可能的解决方案。在(我的)偏好顺序中:
用添加所需 headers:
的自定义代码包装 http.NewRequest
func MyRequest(method, path string, 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
}
这种方法的优点是 straight-forward、non-magical 和便携。它可以与任何 third-party 软件一起使用,添加自己的 headers 或设置自定义传输。
唯一不起作用的情况是您依赖 third-party 库来创建 HTTP 请求。我希望这种情况很少见(根据我自己的经验,我不记得曾经 运行 遇到过这种情况)。即使在这种情况下,也许您可以换行 that 调用。
包装对 client.Do
的调用以添加 headers,并可能添加任何其他共享逻辑。
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
}
这种方法也是 straight-forward,并且具有额外的优势(超过 #1),可以轻松减少其他样板文件。这种通用方法也可以很好地与#1 结合使用。一种可能的 draw-back 是您必须始终直接调用 MyDo
方法,这意味着您不能依赖调用 http.Do
本身的第三方软件。
使用自定义 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)
这种方法的优点是可以与任何其他软件“在幕后”一起工作,因此如果您依赖 third-party 库来创建 http.Request
objects,并致电 http.Do
,这可能是您唯一的选择。
但是,这有一个潜在的缺点,即 non-obvious,如果您使用任何 third-party 也设置自定义传输的软件(无需费心遵守现有的自定义传输),则可能会中断).
最终,使用哪种方法取决于 third-party 软件需要哪种类型的可移植性。但如果这不是问题,我建议使用最明显的解决方案,据我估计,这就是上面提供的顺序。
我知道我可以使用
向每个 HTTP 请求手动添加 headerscli := &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 请求自动添加此 header。
最好的方法是什么?
可以配置 http.Client
以使用自定义传输,它可以处理客户端中的每个请求(在 golang.org/x/oauth2 库中找到此实现)。此示例将 headers 附加到每个 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)
}
}
我知道三种可能的解决方案。在(我的)偏好顺序中:
用添加所需 headers:
的自定义代码包装http.NewRequest
func MyRequest(method, path string, 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 }
这种方法的优点是 straight-forward、non-magical 和便携。它可以与任何 third-party 软件一起使用,添加自己的 headers 或设置自定义传输。
唯一不起作用的情况是您依赖 third-party 库来创建 HTTP 请求。我希望这种情况很少见(根据我自己的经验,我不记得曾经 运行 遇到过这种情况)。即使在这种情况下,也许您可以换行 that 调用。
包装对
client.Do
的调用以添加 headers,并可能添加任何其他共享逻辑。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 }
这种方法也是 straight-forward,并且具有额外的优势(超过 #1),可以轻松减少其他样板文件。这种通用方法也可以很好地与#1 结合使用。一种可能的 draw-back 是您必须始终直接调用
MyDo
方法,这意味着您不能依赖调用http.Do
本身的第三方软件。使用自定义
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)
这种方法的优点是可以与任何其他软件“在幕后”一起工作,因此如果您依赖 third-party 库来创建
http.Request
objects,并致电http.Do
,这可能是您唯一的选择。但是,这有一个潜在的缺点,即 non-obvious,如果您使用任何 third-party 也设置自定义传输的软件(无需费心遵守现有的自定义传输),则可能会中断).
最终,使用哪种方法取决于 third-party 软件需要哪种类型的可移植性。但如果这不是问题,我建议使用最明显的解决方案,据我估计,这就是上面提供的顺序。