必须用 ctx.Values().Set() 传数据,因其线程安全且生命周期贯穿请求;Values 与 ViewData 独立,中间件设 Values,handler 需显式转 ViewData 才能在模板中使用。

中间件里怎么把数据传给后续 handler
必须用 ctx.Values().Set(),不能用局部变量或闭包捕获。Iris 的 Context 实例在每次请求中复用,Values() 是专为此设计的线程安全存储区,底层是 memstore.Store。
常见错误:在中间件里直接赋值一个全局变量或函数外层变量,结果多个并发请求互相覆盖;或者误用 ctx.Params().Set()(它只管 URL 路径参数,不存业务数据)。
-
ctx.Values().Set("user_id", 123)→ 后续 handler 中用ctx.Values().Get("user_id")取,类型是interface{},需断言 - 若要类型安全,建议封装成方法:
ctx.Values().Set("auth_user", &User{ID: 123, Name: "admin"}) - 避免 key 冲突:推荐用自定义常量,比如
const CtxKeyUser = "auth_user",而不是硬写字符串
为什么 ctx.Next() 之后还能取到中间件设的值
因为 ctx.Values() 生命周期绑定整个请求上下文,不是作用域局部变量。ctx.Next() 只是推进 handler 链执行顺序,并不销毁或重置 Values()。
注意:如果中间件调用了 ctx.StopExecution(),后续 handler 不会执行,但已设的值依然保留在当前 ctx 中(不过没人读了)。
- 所有中间件和最终 handler 共享同一个
ctx.Values()实例 - 不需要手动清理,请求结束时整个
ctx被归还到ContextPool,内部自动重置 - 不要在中间件里用
defer ctx.Values().Set(...),defer 在 handler 返回后才执行,此时可能已进入下一个请求周期
模板里怎么用中间件传来的数据
模板无法直接访问 ctx.Values(),必须显式通过 ctx.ViewData() 透出。这是两个独立的数据通道:一个供 handler 间流转(Values),一个专供视图渲染(ViewData)。
典型漏掉的步骤:中间件设了 ctx.Values().Set("role", "admin"),但没在 handler 里转成 ctx.ViewData("Role", ctx.Values().Get("role")),导致模板里 {{.Role}} 是空的。
-
ctx.ViewData()必须在ctx.View()前调用,否则无效 -
ctx.ViewData()不支持嵌套结构体自动展开,如果传的是 map 或 struct,模板里要用{{.UserInfo.Name}}这种点语法 - 若需全局可用(如登录态用户信息),可在全局中间件里统一 set + viewdata,避免每个 handler 重复写
Values 和 ViewData 混用容易踩的坑
两者底层完全无关,Values 是 handler 链通信机制,ViewData 是模板数据注入机制。强行混用会导致逻辑断裂或静默失败。
最常发生的错误:在中间件里调用 ctx.ViewData("X", "val"),以为后续 handler 或模板能拿到——不行,ViewData 只对当次 ctx.View() 生效,且中间件执行时还没到 View 阶段,这个调用会被后续的 ctx.ViewData() 覆盖。
- 中间件只负责设
Values,handler 负责取Values并决定是否透出给模板 - 不要在中间件里调用
ctx.ViewData(),除非你确定该中间件紧邻ctx.View()且无其他 handler 干扰 - 调试时可打印
ctx.Values().Len()和len(ctx.GetViewData())对比,确认数据流向是否符合预期











