Завершить HTTP-запрос от уровня IP с помощью golang - PullRequest
0 голосов
/ 05 июня 2018

Я отправляю HTTP-запрос на сервер, используя golang.Предположим, что сервер в данный момент выключен (означает, что машина, на которой работает сервер, выключен), а затем запрос застревает на уровне IP.Поэтому выполнение моей программы не может продолжаться дальше.Невозможно перейти на прикладной уровень.Так есть ли способ в Голанге, чтобы остановить это.Я использую следующий код.

req, err := http.NewRequest("POST", url, bytes.NewReader(b))
       if err != nil {
               return errors.Wrap(err, "new request error")
       }
resp, err := http.DefaultClient.Do(req)
       if err != nil {
               return errors.Wrap(err, "http request error")
       }
       defer resp.Body.Close()

Есть ли что-нибудь, что можно добавить к этому, чтобы завершить запрос, если он ничего не находит на уровне IP.

Ответы [ 3 ]

0 голосов
/ 05 июня 2018

Использовать нестандартное значение http.Transport с полем DialContext, установленным на функцию, которая использует настраиваемый контекст с правильно настроенным временем ожидания / крайним сроком.Другой вариант - использовать пользовательский net.Dialer.

Что-то вроде этого:

cli := http.Client{
    Transport: &http.Transport{
        DialContext: func (ctx context.Context, network, address string) (net.Conn, error) {
            dialer := net.Dialer{
                Timeout: 3 * time.Second,
            }
            return dialer.DialContext(ctx, network, address)
        },
    },
}

req, err := http.NewRequest(...)
resp, err := cli.Do(req)

Обратите внимание, что согласно документам net.Dialer контекст, передаваемый его DialContext, можетпревзойти тайм-аут, установленный на самой звонилке - это именно то, что нам нужно: поле Timeout звонилки контролирует именно «набор номера» (установление TCP-соединения), в то время как вы можете также включить запрос HTTP в контекст (используя http.Request.WithContext)контролировать время ожидания всего запроса, а также иметь возможность отменить его в любое время (включая шаг набора номера).

Пример игровой площадки .

0 голосов
/ 05 июня 2018

Транспорт @kostix - это, безусловно, то, что вы ищете в этом случае.Транспорт и клиенты безопасны для одновременного использования.Но, пожалуйста, прочитайте о Transport (и я также советую прочитать о клиенте), поскольку существует множество различных способов повлиять на то, как вы обрабатываете неактивные соединения, а не только упомянутый ранее DialContext.

Так как вы можете установить ResponseHeaderTimeout:

ResponseHeaderTimeout, если он не равен нулю, указывает количество времени ожидания заголовков ответа сервера после полной записи запроса (включаяего тело, если есть).Это время не включает время чтения тела ответа.

Или, если вы используете безопасное соединение, вы можете установить TLSHandshakeTimeout:

TLSHandshakeTimeout указывает максимальное количество времени ожидания ожидания рукопожатия TLS.Ноль означает отсутствие тайм-аута.

Для удобства чтения и обслуживания, я также предлагаю, возможно, создать функцию для построения вашего клиента, что-то вроде:

func buildClient(timeout time.Duration) *http.Client {
    tr := &http.Transport{
        IdleConnTimeout:       timeout,
        ResponseHeaderTimeout: timeout,
        TLSHandshakeTimeout:   timeout,
    }
    client := &http.Client{
        Transport: tr,
        Timeout:   timeout,
    }
    return client
}
0 голосов
/ 05 июня 2018

Стандартный клиент http не имеет тайм-аута.Вы можете создать явный http.Client самостоятельно и установить время ожидания:

var cl = &http.Client{
    Timeout: time.Second * 10,
}

resp, err := cl.Do(req)

if err != nil {
    // err will be set on timeout
    return errors.Wrap(err, "http request error")
}
defer resp.Body.Close()

Если сервер больше не отвечает в середине запроса, вы можете обработать время ожидания.

...