Ошибка http.ErrHandlerTimeout
Ошибка http.ErrHandlerTimeout возвращается функцией http.Server.ServeHTTP,
когда обработчик запроса превышает максимально допустимое время выполнения.
Эта ошибка возникает при использовании полей ReadTimeout, WriteTimeout
или IdleTimeout структуры http.Server.
Ошибка указывает на то, что клиентское соединение было закрыто из-за превышения таймаута.
Синтаксис
http.ErrHandlerTimeout
Пример
Давайте создадим HTTP-сервер с таймаутом и обработчиком, который превышает этот таймаут:
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/slow", func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintf(w, "Slow response")
})
server := &http.Server{
Addr: ":8080",
Handler: mux,
ReadTimeout: 1 * time.Second,
WriteTimeout: 1 * time.Second,
}
err := server.ListenAndServe()
if err != nil {
fmt.Println(err)
}
}
Результат выполнения кода при обращении к /slow:
http: Handler timeout
Пример
Давайте проверим, является ли ошибка именно http.ErrHandlerTimeout
и обработаем ее соответствующим образом:
package main
import (
"errors"
"fmt"
"net/http"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/timeout", func(w http.ResponseWriter, r *http.Request) {
time.Sleep(3 * time.Second)
fmt.Fprintf(w, "Completed")
})
server := &http.Server{
Addr: ":8081",
Handler: mux,
WriteTimeout: 1 * time.Second,
}
go server.ListenAndServe()
time.Sleep(100 * time.Millisecond)
resp, err := http.Get("http://localhost:8081/timeout")
if err != nil {
if errors.Is(err, http.ErrHandlerTimeout) {
fmt.Println("Handler timeout detected")
} else {
fmt.Println("Other error:", err)
}
return
}
defer resp.Body.Close()
fmt.Println("Response status:", resp.Status)
}
Результат выполнения кода:
"Handler timeout detected"
Пример
Давайте создадим обработчик с контекстом, который проверяет превышение таймаута и возвращает соответствующий HTTP-статус:
package main
import (
"context"
"fmt"
"net/http"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/context", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
select {
case <-time.After(5 * time.Second):
fmt.Fprintf(w, "Task completed")
case <-ctx.Done():
if ctx.Err() == context.DeadlineExceeded {
http.Error(w, "Request timeout", http.StatusRequestTimeout)
}
}
})
server := &http.Server{
Addr: ":8082",
Handler: mux,
WriteTimeout: 2 * time.Second,
}
go server.ListenAndServe()
time.Sleep(100 * time.Millisecond)
resp, err := http.Get("http://localhost:8082/context")
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
fmt.Println("Response status:", resp.Status)
}
Результат выполнения кода:
"Response status: 408 Request Timeout"
Смотрите также
-
ошибку
http.ErrServerClosed,
которая возникает при закрытии сервера -
функцию
http.Server.ListenAndServe,
которая запускает HTTP-сервер с настройками -
функцию
http.TimeoutHandler,
которая создает обработчик с таймаутом -
функцию
http.Server.Shutdown,
которая корректно завершает работу сервера