不能直接用 context.set() 后在中间件里取不到值,因为 set/get 值仅限当前请求的 iris context 实例,未显式 get、key 不一致、未做类型断言判空或误用标准库 context.value 都会导致取值失败。

为什么不能直接用 context.Set() 后在中间件里取不到值
因为 context.Set() 存的值只在当前请求生命周期内有效,但如果你在中间件中调用 ctx.Next() 之后再尝试 ctx.Get(),而目标 handler 又没显式调用 ctx.Set(),那取到的就是 nil。更常见的情况是:你在前置中间件 set 了值,但后续 handler 没有主动 get,或者用了不同 key 名(大小写、拼写偏差),导致“传值失败”的错觉。
-
Set()和Get()是成对使用的,key 必须完全一致(包括类型,string和intkey 不互通) - 多个中间件链式调用时,只要没被覆盖或清空,值会一直保留在该
context.Context实例上 - 注意 Iris 的
context.Context不是 Go 标准库的context.Context,它不支持WithValue链式传递,别混用
如何安全地在中间件和 handler 之间传结构体或自定义类型
直接存指针或结构体没问题,但要注意生命周期——Iris 的 context 对象本身是复用的(为性能做对象池),所以你存的值不会被自动清理,必须确保不引用已失效的内存(比如闭包捕获局部变量地址)。推荐做法是只存不可变数据或新分配的对象。
- 用
ctx.Set("user", &User{ID: 123, Name: "alice"})是安全的,因为新建了结构体实例 - 避免
ctx.Set("cfg", configPtr),除非你确认configPtr的生命周期覆盖整个请求 - 取值时务必类型断言并判空:
v := ctx.Get("user"); if u, ok := v.(*User); ok { ... } - 如果要传多个字段,建议封装成一个 map 或 struct,而不是分散 set 多个 key
ctx.Values() 和 ctx.Params() 容易混淆的边界
ctx.Params() 只用于解析路由路径参数(如 /user/{id:int} 中的 id),而 ctx.Values()(即 Set/Get 底层存储)才是你手动传值的地方。两者互不干扰,但名字太像,新手常误以为 ctx.Param("xxx") 能取到 Set() 的值。
-
ctx.Param("id")→ 取路由参数,来自 URL 路径 -
ctx.URLParam("token")→ 取查询参数(?token=abc) -
ctx.Get("user")→ 取你中间件或 handler 显式Set()的上下文值 - 没有
ctx.Value("key")这种方法,那是 Go 标准库 context 的写法,Iris 里不存在
跨中间件传值时遇到 panic: “interface conversion: interface {} is nil” 怎么办
这几乎一定是没检查 Get() 返回值是否为 nil 就直接断言。Iris 的 Get() 在 key 不存在时返回 nil,不是零值,所以 u := ctx.Get("user").(*User) 会 panic。
- 永远用两值断言:
if u, ok := ctx.Get("user").(*User); ok { ... } - 或者先判断存在性:
if ctx.IsSet("user") { ... } - 如果某个 key 是强依赖,建议在前置中间件里统一 set 默认值(如
ctx.Set("user", (*User)(nil))),避免下游反复判空 - 调试时可打印
ctx.Values().Len()和fmt.Printf("%+v", ctx.Values().Map())(需 importfmt)看当前存了啥
Set 的值都绑定在单个 context 实例上,不跨请求,也不跨 goroutine —— 如果你启了额外 goroutine 并试图在里面访问 ctx,那大概率拿到的是脏数据或 panic。











