Мне известно о трех возможных решениях этого. В (моем) порядке предпочтения:
Обтекание 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-запросов. Я ожидаю, что это редко (я не помню, чтобы когда-либо сталкивался с этим в моем собственном опыте). И даже в таком случае, возможно, вы можете обернуть в этот вызов .
Перенос вызовов на 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
, это может быть ваш единственный вариант.
Однако у этого есть потенциальный недостаток: он неочевиден и, возможно, ломается, если вы используете стороннее программное обеспечение, которое также устанавливает пользовательский транспорт (не удосуживаясь удовлетворить существующий пользовательский транспорт).
В конечном итоге, какой метод вы используете, будет зависеть от того, какой тип переносимости вам нужен со сторонним программным обеспечением. Но если это не проблема, я предлагаю использовать наиболее очевидное решение, которое, по моей оценке, является приведенным выше.