Ce face net/http.TimeoutHandler
http.TimeoutHandler(h, 2*time.Second, "serverul este ocupat") returnează un handler care rulează h cu o limită de timp. Dacă h termină la timp, răspunsul lui ajunge normal la client. Dacă nu, clientul primește 503 Service Unavailable cu mesajul dat, iar scrierile ulterioare ale lui h eșuează cu http.ErrHandlerTimeout.
Contextul cererii (r.Context()) primit de h este anulat la expirare, deci un handler bine scris se oprește singur. Spre deosebire de WriteTimeout din http.Server, limita se aplică doar handler-elor pe care le împachetezi și clientul primește un răspuns clar.
Parametri
| Parametru | Descriere |
|---|---|
h |
Handler-ul de limitat. |
dt |
Timpul maxim. |
msg |
Corpul răspunsului 503 (gol = un mesaj HTML implicit). |
Ce returnează
Un http.Handler nou.
Exemple
Exemplul 1: Raport rapid și raport lent
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"time"
)
func raport(w http.ResponseWriter, r *http.Request) {
durata, _ := time.ParseDuration(r.URL.Query().Get("durata"))
select {
case <-time.After(durata):
fmt.Fprint(w, "raport generat")
case <-r.Context().Done():
// limita a expirat; ne oprim
}
}
func main() {
h := http.TimeoutHandler(http.HandlerFunc(raport), 100*time.Millisecond, "raportul durează prea mult, încearcă mai târziu")
for _, d := range []string{"10ms", "2s"} {
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest("GET", "/raport?durata="+d, nil))
fmt.Printf("durata=%-5s %d %s\n", d, rec.Code, rec.Body.String())
}
}
Rezultat
durata=10ms 200 raport generat
durata=2s 503 raportul durează prea mult, încearcă mai târziu
Exemplul 2: Limită doar pe o rută
Doar /export are limită. Cu mesajul gol, Go trimite o mică pagină HTML implicită.
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"time"
)
func main() {
lent := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
select {
case <-time.After(time.Second):
fmt.Fprint(w, "export gata")
case <-r.Context().Done():
}
})
mux := http.NewServeMux()
mux.Handle("/export", http.TimeoutHandler(lent, 50*time.Millisecond, ""))
mux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "pong") })
srv := httptest.NewServer(mux)
defer srv.Close()
for _, cale := range []string{"/ping", "/export"} {
resp, err := http.Get(srv.URL + cale)
if err != nil {
fmt.Println(err)
return
}
corp, _ := io.ReadAll(resp.Body)
resp.Body.Close()
fmt.Printf("%-8s %s | %s\n", cale, resp.Status, corp)
}
}
Rezultat
/ping 200 OK | pong
/export 503 Service Unavailable | <html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>
Greșeli frecvente
- Handler-ul ignoră
r.Context()și continuă să lucreze după expirare: clientul a primit 503, dar serverul consumă resurse degeaba. - Folosești
TimeoutHandlerpentru răspunsuri transmise în flux (streaming): nu suportăhttp.Flusher.
Comenzi înrudite
net/http.Server: Serverul HTTP configurabil: adresă, handler, limite de timp; ListenAndServe îl pornește, Shutdown îl oprește curat.context.WithTimeout: Creează un context care se anulează singur după durata dată; limita de timp standard pentru cereri și interogări.net/http.Handler: Interfața oricărui obiect care răspunde la cereri HTTP (metoda ServeHTTP); HandlerFunc transformă o funcție în Handler.