中间件本身不慢,慢的是在其中执行读取请求体、重复解析json、每次新建grpc连接等不当操作;应避免无条件调用ctx.readjson(),仅对特定路径或错误状态码条件解析,禁用logrequestbody/logresponsebody,默认false,grpc.dial()须在app.run前一次性完成并注入,ctx.next()不可跨goroutine调用。

中间件本身不慢,慢的是你在里面干了不该干的事——比如读完整个请求体、重复解析 JSON、或在每次请求里新建 gRPC 连接。
避免在中间件里调用 ctx.ReadBody() 或 ctx.ReadJSON()
这类方法会提前消费 ctx.Request().Body,导致后续 handler 再调用时返回空或 panic。Iris 的 body 只能被读一次,且不可 rewind。
- 错误做法:在日志中间件里无条件调用
ctx.ReadJSON(&v)记录入参 - 正确做法:只对特定路径(如
/debug/)或错误状态码(statusCode >= 400)做条件解析 - 若必须记录原始 body,用
ctx.Request().Body手动读取并重置(需io.NopCloser(bytes.NewReader(buf))),但会增加内存拷贝开销,慎用
禁用 LogRequestBody 和 LogResponseBody
默认开启的 iris.Logger 若设了 LogRequestBody: true,会对每个请求缓存整个 body 字节流,尤其 POST 大 JSON 时,GC 压力陡增,QPS 明显下滑。
- 生产环境务必设为
false:app.Logger().SetLevel(iris.WarnLevel); app.Use(iris.Logger(iris.LoggerConfig{LogRequestBody: false, LogResponseBody: false})) - 调试时可用轻量替代:仅记录
ctx.GetHeader("X-Request-ID")和耗时,不碰 body - 注意:自定义中间件若用了
ctx.PostValues()或ctx.FormValue(),本质也是读 body,同样触发消耗
全局复用连接类资源,别在中间件里 grpc.Dial()
中间件是每请求必经之路,若在里面调 grpc.Dial(),等于每秒新建数百个 TCP+TLS 连接,很快触发 too many open files 错误。
- 正确时机:在
app.Run前一次性 dial,并用app.RegisterValue()注入 - 错误写法示例:
func authMiddleware(ctx iris.Context) { conn, _ := grpc.Dial("...") // ❌ 每次都建连 } - 注入后 controller 构造函数可接收,但注意 Iris 不支持接口字段注入,别把
itempb.ItemServiceClient写成 struct 字段
中间件中别用 go func() { ctx.Next() }
ctx.Next() 只在当前 goroutine 生效,跨 goroutine 调用会导致链中断、handler 不执行、响应不写出,且无任何报错提示。
- 典型误用场景:异步打日志、上报监控指标时起 goroutine 后调
ctx.Next() - 正确方式:同步执行逻辑,耗时操作改用 channel + select 控制超时,或移至 handler 后续阶段
- 若真需并发,确保 ctx 数据已提取完毕(如
id := ctx.Param("id")),再传原始值进 goroutine,而非传 ctx
真正卡性能的从来不是中间件注册本身,而是你把它当成了“万能钩子”,往里塞了本该在 handler 里做、或压根不该做的事。越靠近请求入口,越要克制。











