Go 的 HTTP 超时分散在 Server、Transport、Client、context 好几处,每个管的阶段不同。这篇逐个用真实运行验证它们各自管什么、不管什么,尤其是 WriteTimeout 和 ResponseHeaderTimeout 这两个最容易被误解的。
ReadHeaderTimeout = 0s 客户端只发了半个请求头就不再发:3001 ms后——3 秒内服务器没有关闭连接 ReadHeaderTimeout = 200ms 客户端只发了半个请求头就不再发:200 ms后——服务器关闭了连接,客户端收到 0 字节
不设 ReadHeaderTimeout,客户端发半个请求头后就不动,连接可以一直占着(实验里等了 3 秒还在);设 200 ms 后 200 ms 就被关。对外服务必须设置。
handler 睡了 500 ms,写响应时 err = <nil> WriteTimeout = 200 ms,handler 要 500 ms:客户端在 502 ms 后看到:服务器关闭了连接,客户端收到 0 字节
handler 睡 500 ms,WriteTimeout 只有 200 ms:handler 并没有被取消,它写响应时也没报错(写进了缓冲),但客户端 502 ms 后只看到连接被关,0 字节。
IdleTimeout = 300 ms,一个请求完成后连接保持空闲:301 ms 后服务器关闭了连接(客户端读到 EOF)
IdleTimeout 控制 keep-alive 连接空闲多久被回收:实验里设 300 ms,301 ms 后服务器关闭了连接。
http.TimeoutHandler(100 ms),handler 要 500 ms:101 ms 后客户端收到 503 Service Unavailable,body "服务超时"(err=<nil>) handler 里 r.Context() 的状态:context deadline exceeded
想让慢 handler 能提前结束,用 http.TimeoutHandler:100 ms 后客户端得到 503 和自定义文字,handler 的 r.Context() 也变成 deadline exceeded——但 handler 要自己监听才会收手。
Client.Timeout=300ms 响应头立刻到;读 body 301 ms 后结束,读到 3 字节,err = context deadline exceeded (Client.Timeout or context cancellation while reading body) Transport.ResponseHeaderTimeout=300ms 响应头立刻到;读 body 1012 ms 后结束,读到 10 字节,err = <nil> ctx WithTimeout(300ms) 响应头立刻到;读 body 301 ms 后结束,读到 3 字节,err = context deadline exceeded
服务端先发响应头、再每 100 ms 发 1 字节。Client.Timeout 与 ctx 超时都会截断读 body(读到 3 字节);Transport.ResponseHeaderTimeout 只管等响应头,body 慢也不会超时(读完 10 字节用了约 1 秒)。想限制整个请求的时长用前两者。
Dialer.Timeout = 300 ms,连接 10.255.255.1:80:301 ms 后返回:dial tcp 10.255.255.1:80: i/o timeout
往不可达的地址连接,Dialer.Timeout 设 300 ms 就在 301 ms 后返回 i/o timeout。Transport 的 DialContext 里要自己设这个超时。
ReadHeaderTimeout is the amount of time allowed to read request headers. The connection's read deadline is reset after reading the headers and the Handler can decide what is considered too slow for the body. If zero, the value of WriteTimeout is the maximum duration before timing out writes of the response. It is reset whenever a new request's header is read. Like ReadTimeout, it does not let Handlers make decisions on a per-request basis. A zero or negative value means there will be no timeout. IdleTimeout is the maximum amount of time to wait for the next request when keep-alives are enabled. If zero, the value of ReadTimeout is used. If negative, or if zero and ReadTimeout is zero or negative, there is no timeout.
ReadHeaderTimeout 管读请求头,读完后读截止时间重置;WriteTimeout 每读到新请求头就重置,不让 Handler 逐请求决定;IdleTimeout 管 keep-alive 下等下一个请求,为零时借用 ReadTimeout。