Нужно ли читать и закрывать тело ответа, чтобы повторно использовать TCP-соединение при повторной попытке? - PullRequest
0 голосов
/ 06 августа 2020

Я выполняю повторную попытку, используя http.RoundTripper в Go. Вот пример реализации.

type retryableRoundTripper struct {
    tr            http.RoundTripper
    maxRetryCount int
}

func (t *retryableRoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) {
    for count := 0; count < t.maxRetryCount; count++ {
        log.Printf("retryableRoundTripper retry: %d\n", count+1)
        resp, err = t.tr.RoundTrip(req)

        if err != nil || resp.StatusCode != http.StatusTooManyRequests {
            return resp, err
        }
    }

    return resp, err
}

Вопросы

Нужно ли читать и закрывать тело ответа, чтобы повторно использовать TCP-соединение при повторной попытке?

func (t *retryableRoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) {
    for count := 0; count < t.maxRetryCount; count++ {
        log.Printf("retryableRoundTripper retry: %d\n", count+1)
        resp, err = t.tr.RoundTrip(req)

        if err != nil || resp.StatusCode != http.StatusTooManyRequests {
            return resp, err
        }
    }

    // add
    io.Copy(ioutil.Discard, resp.Body)
    resp.Body.Close()

    return resp, err
}

Кстати, я написал тест и подтвердил, что повторные попытки работают должным образом. (В Go Playground время истекает, но работает локально.)

https://play.golang.org/p/08YWV0kjaKr

1 Ответ

2 голосов
/ 06 августа 2020

Конечно, вам необходимо прочитать соединение с , чтобы могло быть повторно использовано, и закрытие соединения требуется, как указано в документации.

Как указано в документации:

Клиент должен закрыть тело ответа по завершении работы с ним

и

Транспортный протокол HTTP-клиента по умолчанию не может повторно использовать HTTP / 1.x "keep -alive "TCP-соединения, если тело не прочитано до конца и не закрыто.

Если сервер хочет отправить больше данных, чем помещается в начальных буферах чтения, он будет заблокирован отправкой ответа . Это означает, что если транспортный механизм попытается отправить новый запрос по этому соединению, сервер не сможет его обработать, потому что он никогда не завершил первый запрос. Обычно это приводит к ошибке клиента connection reset by peer и ошибке сервера write: broken pipe.

Если вы хотите попытаться повторно использовать соединение, но ограничить объем чтения, используйте io.LimitedReader и / или проверьте значение ContentLength. Таким образом, вы можете отказаться от соединения, если быстрее обработать ошибки и установить новое соединение, чем читать неограниченный объем данных. См. Ограничение количества данных, считываемых в ответ на запрос HTTP GET .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...