必须调用app.ContextPool.Attach()注册自定义Context构造函数,且结构体需嵌入context.Context;还需重写Next()和Do()方法,否则handler中无法调用自定义方法。

怎么让自定义 Context 方法在 handler 里生效
必须通过 app.ContextPool.Attach() 注册构造函数,否则 Iris 仍用默认 context.Context 实例,你写的任何方法都不会被调用。这个步骤漏掉,是 90% 自定义 Context 失效的根源。
构造函数返回的是你自己的结构体指针(比如 *MyContext),且该结构体必须嵌入 context.Context ——不是继承,是组合;否则无法复用原生方法,也过不了类型断言校验。
常见错误现象:
- 写了
func (c *MyContext) HTML(...),但 handler 里调ctx.HTML()报错:undefined method - handler 中
fmt.Printf("%T", ctx)打印出*context.Context而非*MyContext - 中间件里能调用自定义方法,但路由 handler 里不行——说明注册时机不对或没覆盖完整链路
正确做法是:在 app := iris.New() 之后、任何路由注册之前,立刻调用 app.ContextPool.Attach()。
为什么必须重写 Next() 和 Do()
这两个方法是 Iris 请求链调度的核心入口。如果你只覆盖了 HTML() 却没重写 Next(),那么中间件调 ctx.Next() 时实际执行的是原始 context.Next(),传入的仍是默认 context.Context 类型,导致后续 handler 拿不到你的自定义方法。
Do() 同理:它负责启动整个处理器链,不重写就会跳过你的结构体上下文初始化逻辑。
最小必要重写模板:
func (c *MyContext) Next() {
context.Next(c)
}
func (c *MyContext) Do(handlers context.Handlers) {
context.Do(c, handlers)
}
注意参数类型必须是你自己的 *MyContext,不能是 context.Context,否则运行时类型不匹配。
如何安全添加新字段和方法而不破坏复用机制
Iris 的 Context 是从 sync.Pool 复用的,所以你加的字段不能依赖初始化时的闭包变量或外部指针,否则可能读到上一次请求残留的数据。
推荐做法:
- 新增字段用值类型(
int,string,time.Time)或每次新建的结构体(&User{...}),避免存全局配置指针 - 如果要缓存计算结果(如解析后的 JWT claims),用
ctx.Values().Set("claims", c)而不是直接塞进结构体字段——因为Values()是 per-request 安全的 - 不要在自定义方法里修改
ctx.Request().Context(),Iris 不依赖标准库context.Context传值,混用会导致 key 冲突或取不到值 - 所有新增方法签名必须和原接口一致,返回值、参数顺序、指针接收者都不能变
调试时怎么确认当前 ctx 真的是你的类型
最直接的办法是在任意 handler 或中间件开头加一行:
fmt.Printf("ctx type: %T\n", ctx)
如果输出是 *main.MyContext,说明 Attach 成功;如果是 *context.Context,说明注册失败或被覆盖。
另一个容易忽略的点:app.ContextPool.Attach() 只影响后续新建的 Context 实例,已存在的(比如测试中手动 new 出来的)不会变。单元测试里若用 iris.New().Handler(...) 模拟请求,记得也传入你自己的构造函数,否则测不出问题。
最后提醒:自定义 Context 是高级用法,80% 的场景用 ctx.Set()/ctx.Get() + 全局中间件就能解决。只有当你需要深度拦截 JSON()、Redirect() 行为,或统一注入大量业务方法时,才值得投入成本定制。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











