Iris 中应使用 ctx.OnResponse() 而非 defer 记录真实耗时和状态码,因 defer 无法捕获 panic、中间件中断或响应写出延迟;OnResponse 确保在响应真正 flush 后执行,且兼容异常场景。

为什么直接用 time.Now() 和 defer 在 Iris 中不准
因为 defer 触发时机是函数 return 前,但 Iris 的 handler 可能因 panic、中间件提前中断(如鉴权失败调 ctx.StopExecution())、或底层连接断开而根本不会走到 defer;更关键的是,time.Since(start) 算出的只是 handler 执行时间,不包含响应真正写出并 flush 到客户端的耗时——用户感知的延迟其实发生在这里。
必须用 ctx.OnResponse() 捕获真实状态码和完成时刻
Iris 的 ctx.StatusCode() 是 setter,不是 getter;真实状态码只有在响应写出后才确定。正确做法是在中间件开头记时间,在 ctx.OnResponse() 钩子里读取最终状态和耗时:
- 开头:
start := time.Now() - 注册钩子:
ctx.OnResponse(func() { duration := time.Since(start); status := ctx.ResponseWriter().Status() }) - 切勿在
OnResponse里调ctx.StatusCode()或写响应,会 panic - 别依赖
ctx.Values().Get("duration")—— 这个值在WrapRouter场景下不可靠
避免在日志中间件里读 ctx.Request().Body
调 ctx.ReadBody() 或 ctx.PostValues() 会消费请求流,后续 handler 再调 ctx.ReadJSON() 就返回空或 error。生产环境默认关掉日志体采集:iris.Logger().WithRequestBody(false).WithResponseBody(false);如需调试,只对错误响应(status >= 400)条件记录 request ID 和摘要。
结构化日志字段要精简,别拼 JSON
高频打点时,格式化和序列化是性能瓶颈。中间件只存原始值:method、path、status、duration.Milliseconds()、ctx.RemoteAddr();用原子操作更新指标(如 metrics.HTTPDuration.Observe(duration.Seconds())),聚合计算交给 Prometheus Histogram;慢请求(如 >500ms)再额外记录 traceID 和完整路径。
立即学习“go语言免费学习笔记(深入)”;
最易被忽略的一点:耗时终点必须锚定在响应写出完成那一刻,不是 handler 返回、不是 ctx.Next() 结束、也不是 defer 执行——只有 OnResponse 钩子能保证这点,且它天然兼容 panic 恢复和连接异常场景。


















