Как установить таймаут для HTTP-запроса в Go?

Ответ

В Go есть несколько способов установить таймаут для HTTP-запроса, каждый из которых подходит для разных сценариев.

Способ 1: http.Client.Timeout (Простой и общий)

Это самый простой способ. Timeout устанавливает общий лимит времени на весь запрос, включая установку соединения, отправку запроса и чтение всего тела ответа.

client := &http.Client{
    Timeout: 5 * time.Second, // Общий таймаут
}

resp, err := client.Get("https://example.com")
if err != nil {
    // Ошибка может быть вызвана таймаутом, например: context.DeadlineExceeded
    log.Fatal(err)
}
defer resp.Body.Close()

Способ 2: context.WithTimeout (Гибкий и предпочтительный)

Использование контекста — более современный и гибкий подход. Он позволяет отменить запрос не только по таймауту, но и по другим причинам (например, если пользователь отменил операцию). Контекст передается через всю цепочку вызовов.

// Создаем контекст с таймаутом в 5 секунд
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() // Важно вызывать cancel, чтобы освободить ресурсы

req, _ := http.NewRequestWithContext(ctx, "GET", "https://example.com", nil)

resp, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

Способ 3: http.Transport (Детальный контроль)

Для тонкой настройки таймаутов на разных этапах запроса можно сконфигурировать http.Transport.

client := &http.Client{
    Transport: &http.Transport{
        DialContext: (&net.Dialer{
            Timeout:   3 * time.Second, // Таймаут на установку TCP-соединения
        }).DialContext,
        TLSHandshakeTimeout:   4 * time.Second, // Таймаут на TLS-рукопожатие
        ResponseHeaderTimeout: 5 * time.Second, // Таймаут на ожидание заголовков ответа
    },
}

resp, err := client.Get("https://example.com")
// ...

Какой способ выбрать?

  • Client.Timeout: Для простых утилит и быстрых скриптов.
  • context.WithTimeout: Предпочтительный способ для большинства приложений, особенно для серверных, где важна управляемая отмена операций.
  • http.Transport: Для случаев, когда нужен гранулярный контроль над сетевыми таймаутами (например, для обнаружения медленных серверов, которые долго устанавливают соединение, но быстро отвечают).