Добавьте заголовки для каждого HTTP-запроса с помощью клиента - PullRequest
0 голосов
/ 08 января 2019

Я знаю, что могу добавить заголовки к каждому 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 голосов
/ 08 января 2019

Мне известно о трех возможных решениях этого. В (моем) порядке предпочтения:

  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, это может быть ваш единственный вариант.

    Однако у этого есть потенциальный недостаток: он неочевиден и, возможно, ломается, если вы используете стороннее программное обеспечение, которое также устанавливает пользовательский транспорт (не удосуживаясь удовлетворить существующий пользовательский транспорт).

В конечном итоге, какой метод вы используете, будет зависеть от того, какой тип переносимости вам нужен со сторонним программным обеспечением. Но если это не проблема, я предлагаю использовать наиболее очевидное решение, которое, по моей оценке, является приведенным выше.

0 голосов
/ 08 января 2019

Можно настроить 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)
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...