Iris 中 HTTP 超时需分层配置:server 层用 iris.Configuration 设置 Read/Write/IdleTimeout;业务层在 handler 内用 context.WithTimeout 控制外部调用;底层调优通过 ConfigureHost 修改 *http.Server 字段。

Run() 传入 Configuration 控制超时
直接用 iris.Configuration 设置全局 HTTP 超时,是最常用也最可控的方式。Iris v12+ 推荐统一走 app.Run(iris.Addr(":8080"), iris.Configuration{...}),而不是旧版的 Listen() —— 后者不支持超时配置。
常见错误现象:加了 ReadTimeout 却没生效,或者 handler 里 time.Sleep(10 * time.Second) 还是没被中断。
原因在于:超时是 HTTP server 层级的控制,只作用于连接建立、请求头读取、响应写入等阶段;它不会 kill 正在运行的 goroutine,也不会自动 cancel handler 内部逻辑。
实操建议:
-
ReadTimeout控制从客户端读完请求头 + 请求体的最大耗时(含 body 解析),设太短会导致 JSON 或表单上传失败 -
WriteTimeout控制从 handler 开始写响应到写完的总时间,设太短可能中断大文件下载或流式响应 -
IdleTimeout控制 keep-alive 连接空闲多久后关闭,防连接堆积,建议设为 60s 左右 - 示例:
app.Run(iris.Addr(":8080"), iris.Configuration{ ReadTimeout: 10 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 60 * time.Second, })
Handler 内部用 context.WithTimeout 主动控制业务逻辑
HTTP server 超时不等于业务超时。比如你调第三方 API、查数据库、渲染模板,这些都得自己加 context.WithTimeout,否则即使 server 超时断连,goroutine 还在后台跑。
常见错误现象:curl 看到 504 Gateway Timeout,但服务进程 CPU 持续飙高,日志里发现大量未结束的 DB 查询。
实操建议:
- 别用
time.AfterFunc或全局 timer,必须基于 handler 入参的ctx.Request().Context()衍生子 context - 调用外部服务(如钉钉 Webhook)时,
http.Client必须配Timeout字段,且该值 ≤ handler context 的 timeout,否则无意义 - DB 查询要传 context,例如
db.QueryRowContext(ctx, sql, args...),否则超时无效 - 示例:
func(c *MyController) GetData(ctx iris.Context) { ctxWithTimeout, cancel := context.WithTimeout(ctx.Request().Context(), 5*time.Second) defer cancel() <pre class="brush:php;toolbar:false;">resp, err := http.DefaultClient.Do(req.WithContext(ctxWithTimeout)) // ... 处理}
ConfigureHost 里改 *http.Server 的 MaxConns 和 Timeout 字段
当需要更底层控制(比如限制并发连接数、细粒度调优),就得用 ConfigureHost。它在 Run() 内部被调用,能拿到原始 *http.Server 实例。
注意:这个方法不是为了替代 Configuration,而是补充。比如你想让每个连接最多处理 100 个请求后主动关闭(防长连接内存泄漏),就必须在这里设 MaxConnsPerHost 或 MaxIdleConns。
实操建议:
-
MaxConns是整个 server 的并发连接上限,设太高可能触发系统 open files 限制 -
ReadHeaderTimeout比ReadTimeout更精细——只管请求头读取,不管 body,适合对 header 解析要求严的场景 - 修改前务必检查 ulimit -n,避免启动时报
too many open files - 示例:
app.ConfigureHost(func(su *iris.Supervisor) { su.Server.MaxConns = 5000 su.Server.ReadHeaderTimeout = 2 * time.Second su.Server.MaxIdleConns = 100 })
别混淆 ctx.Timeout() 和 server 层超时
ctx.Timeout() 是 Go 标准库 context.Context 的方法,返回的是该 context 的 deadline 时间戳(如果设置了的话)。Iris 的 iris.Context 不会自动给每个请求注入带 timeout 的 context,除非你手动用 context.WithTimeout 包裹过。
新手常踩的坑:在中间件里写 if d, ok := ctx.Timeout(); ok { ... },结果永远进不去分支——因为默认 context 没 deadline。
实操建议:
- 不要依赖
ctx.Timeout()判断是否超时,而应监听ctx.Done()并检查ctx.Err() - 若需统一注入超时 context,可在全局中间件里做:
ctx.Request().WithContext(context.WithTimeout(...)),但要注意别覆盖已有 deadline - 真正要判断 handler 是否被 server 中断,看
ctx.ResponseWriter().Status()是否为 0(未写状态)或日志中是否有http: Handler timeout错误
超时不是开关,是分层策略:server 层保连接稳定,handler 层保业务可控,context 层保调用链可中断。漏掉任何一层,都可能让“设置超时”变成一句空话。


















