2 回答
TA贡献1784条经验 获得超7个赞
我知道三种可能的解决方案。按照(我的)偏好顺序:
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
}
这种方法的优点是直接、非魔法且可移植。它将与添加自己的标头或设置自定义传输的任何第三方软件一起使用。
唯一不起作用的情况是您依赖第三方库来创建 HTTP 请求。我希望这种情况很少见(我不记得在我自己的经历中遇到过这种情况)。即使在这种情况下,也许您也可以改为包装该调用。
包装调用以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。
使用自定义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,这可能是您唯一的选择。
但是,这具有不明显的潜在缺点,如果您使用任何也设置自定义传输的第三方软件(无需费心遵守现有的自定义传输),则可能会中断。
最终,您使用哪种方法将取决于您需要第三方软件的可移植性类型。但如果这不是问题,我建议使用最明显的解决方案,据我估计,这就是上面提供的顺序。
TA贡献1862条经验 获得超7个赞
可以配置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)
}
}
- 2 回答
- 0 关注
- 136 浏览
添加回答
举报