net/http 服务端超时怎么控制?keep-alive 又是怎么回事?

一句话结论:http.Server 提供四类超时:ReadHeaderTimeout 防慢请求头(slowloris)、ReadTimeout 限制读完整个请求与 body、WriteTimeout 限制写响应、IdleTimeout 控制 keep-alive 空闲连接;业务处理自身的耗时则用 http.TimeoutHandler 或 context 超时兜底。keep-alive 默认开启(连接复用),IdleTimeout 不设则回落到 ReadTimeout。

字段与建议

字段管什么建议
ReadHeaderTimeout从连接建立到读完请求头必设,如 5s,防 slowloris
ReadTimeout读完整个请求(含 body)有上传就设,如 30s
WriteTimeout写完响应(防慢客户端)如 30s;注意约束长轮询类接口
IdleTimeoutkeep-alive 空闲连接存活如 60s;为 0 时取 ReadTimeout 值
MaxHeaderBytes请求头上限默认 1MB,可按需调小

HTTP/2 下 WriteTimeout 的语义与 HTTP/1.1 不同,别指望它精确限制单个流;应用层业务超时统一交给 TimeoutHandler 或 context.WithTimeout 更可控。

keep-alive 补充

  • 默认开启:同一 TCP 连接服务多个请求,省去反复握手,吞吐更高。
  • 关闭:服务端 srv.SetKeepAlivesEnabled(false),或要求客户端发 Connection: close。
  • 客户端侧:用 http.Client{Timeout: ...} 设总超时,Transport 的 DialContext / IdleConnTimeout / TLSHandshakeTimeout 管连接细节。

配置示例

srv := &http.Server{
	Addr:              ":8080",
	Handler:           http.TimeoutHandler(mux, 10*time.Second, "timeout"),
	ReadHeaderTimeout: 5 * time.Second,
	ReadTimeout:       30 * time.Second,
	WriteTimeout:      30 * time.Second,
	IdleTimeout:       60 * time.Second,
}
log.Fatal(srv.ListenAndServe())

TimeoutHandler 到达时限后向客户端返回 503,并切断与 handler 的关联,防止 handler 无限挂起占资源。

常见追问 / 记忆点

  • 追问:只设 ReadTimeout 不设 ReadHeaderTimeout 行吗?——行但不推荐:ReadTimeout 从连接建立起算,慢请求头攻击仍可能得手。
  • 追问:keep-alive 关掉会怎样?——每次请求都重新建连,握手开销放大,QPS 明显下降。
  • 记忆点:Header 超时防 slowloris;IdleTimeout 管 keep-alive;业务耗时交给 TimeoutHandler/context。
笔记加载中…