Timeout 中间件
给普通 HTTP 请求设置最大执行时间
middleware/timeout 会为请求创建带超时的 context.Context,并在超时后返回 408 Request Timeout。它适合保护普通 HTTP API,避免慢请求长期占用连接和 goroutine。
安装
go get github.com/duxweb/runa/middleware
基本用法
import "github.com/duxweb/runa/middleware/timeout"
route.Default().Use(timeout.New())
默认超时是 30s,默认响应文本是 request timeout
自定义超时
route.Default().Use(timeout.New(timeout.Config{
Timeout: 10 * time.Second,
Message: "request timeout",
}))
给长任务跳过
route.Default().Use(timeout.New(timeout.Config{
Timeout: 5 * time.Second,
Next: func(ctx *route.Context) bool {
return ctx.Request().URL.Path == "/exports"
},
}))
导出、上传、SSE、长轮询等请求不一定适合全局短超时,可以用 Next 跳过,再单独设计超时策略。
WebSocket 和 Upgrade
WebSocket 等 Upgrade 请求会自动跳过 timeout。原因是这类连接本来就是长连接,不应该按普通 HTTP 请求超时处理。
配置项
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Next |
func(*route.Context) bool |
nil |
返回 true 时跳过 |
Timeout |
time.Duration |
30 * time.Second |
请求最大执行时间 |
Message |
string |
request timeout |
超时响应文本 |
和 context 的关系
handler 内应该优先使用 ctx.Context() 传给数据库、缓存、HTTP 客户端等下游调用:
route.Default().Get("/users", func(ctx *route.Context) error {
users, err := service.ListUsers(ctx.Context())
if err != nil {
return err
}
return ctx.JSON(users)
})
这样 timeout 触发后,下游调用才有机会尽快取消。
和 security 的关系
security.New(...) 默认包含 timeout,生产默认 30s,开发预设 120s。可以这样调整:
route.Default().Use(security.New(
security.Production(),
security.Timeout(15*time.Second),
))
常见问题
- timeout 不能强杀已经跑起来的业务代码,只能取消 request context 并停止正常响应
- 如果 handler 在超时后继续写响应,写入会被丢弃或无效
- 对 WebSocket、SSE、长任务接口要谨慎使用全局 timeout