最常用且最安全的上下文参数传递方式是直接调用 ctx.Values().Set("key", value);Iris 的 ctx.Values() 是请求独享、无需手动清理的内存存储,误用 ctx.Set() 或原生 context 均无效,中间件注册须在路由前并调用 ctx.Next() 才能生效。

中间件里怎么往 ctx.Values() 写参数
直接调 ctx.Values().Set("key", value) 就行,这是最常用也最安全的上下文参数传递方式。Iris 的 ctx.Values() 是一个请求生命周期内独享的内存存储,不会跨请求污染,也不需要手动清理。
常见错误是误用 ctx.Set() 或试图往 ctx.Request().Context() 里塞值——这两个都无效,前者不存在,后者是 Go 原生 context,和 Iris 的上下文解耦。
-
ctx.Values().Set("user_id", 123)→ 后续 handler 可用ctx.Values().GetInt64("user_id")安全取值 - 字符串值优先用
GetString(),避免类型断言 panic;数字类用GetInt64()/GetBool()等配套方法 - 不要存指针或闭包,尤其别存数据库连接、文件句柄等需手动释放的资源——
ctx.Values()不负责生命周期管理 - 如果值是结构体,确保字段可导出(首字母大写),否则
JSON序列化时会丢字段
中间件注册顺序必须在路由之前
app.Use() 必须出现在所有 app.Get()、app.Post() 等路由注册之前,否则中间件根本不会执行,你写的 ctx.Values().Set() 自然没机会运行。
典型错误顺序:app.Get("/user", h); app.Use(authMw) —— 这里 authMw 对 /user 路由完全无效。
- 正确顺序:先
app := iris.New()→ 再app.Use(authMw)→ 然后才app.Get(...) - 分组路由同理:
api := app.Party("/api"); api.Use(jwtMw); api.Get("/me", h) - 如果用了 MVC,中间件要注册到
mvc.New(party)实例上,而不是全局app上,否则对 MVC 控制器不生效
为什么 ctx.Values() 取不到中间件设的值
最常踩的坑不是代码写错,而是 handler 没走中间件链——比如你写了 app.Get("/x", h),但忘了 app.Use(mw),或者中间件里漏了 ctx.Next()。
ctx.Next() 是关键:它告诉 Iris 继续执行后续 handler。没有它,中间件执行完就停了,后续路由 handler 根本不触发,自然看不到你设的值。
- 中间件末尾必须加
ctx.Next(),除非你明确想中断流程(比如鉴权失败后ctx.StopWithStatus(iris.StatusUnauthorized)) - 别在中间件里 return 早退,除非配合
StopExecution()或状态码终止 - 用
ctx.IsStopped()可以判断是否已被前面中间件终止,避免重复设值或冲突 - 调试时打印
ctx.HandlerName()和ctx.Path(),确认当前执行的是哪个 handler
ctx.Values() 和依赖注入的区别
ctx.Values() 是运行时键值对,适合传简单数据(ID、token、flag);而 Iris 的依赖注入(如 mvc.Application.Register)是编译期绑定,适合传服务实例(DB、Cache、Logger)。
两者不互斥,但别混用场景:比如把 *sql.DB 塞进 ctx.Values() 是危险的,既浪费内存,又绕过连接池管理。
- 传“请求级”数据:用户 ID、请求 trace ID、权限角色 →
ctx.Values() - 传“应用级”服务:数据库连接池、Redis 客户端、配置对象 →
mvc.Application.Register()或构造函数注入 - MVC 控制器里取
ctx.Values(),直接用c.Ctx.Values().GetXXX(),不是c.Values()(后者不存在) - 别在控制器 BeforeActivation 阶段读
ctx.Values()—— 此时ctx还没创建


















