★ 中间件机制:Next()/Exit()/中间件顺序

结论:中间件是 GoFrame 对请求处理链的 AOP 拦截机制,采用洋葱模型:注册顺序即执行顺序,r.Middleware.Next() 放行到下一层,r.Exit() 立即终止整个请求流程;不调用 Next 则后续处理器不会执行。

一、执行模型

中间件A(前) → 中间件B(前) → Handler → 中间件B(后) → 中间件A(后)
  • Next 之前的代码:请求进入时先执行(鉴权、日志开始等)。
  • Next 之后的代码:Handler 返回后执行(耗时统计、响应加工等)。
  • 多个中间件按注册顺序排列,先注册的先执行前半段、后执行后半段。

二、注册位置

位置写法生效范围
全局s.Use(MiddlewareLog, MiddlewareAuth)所有请求
分组group.Middleware(...)该路由组
路由级g.Meta 的 middleware 标签/单接口注册单个接口

代码示例

// 鉴权:不通过直接终止链路
func MiddlewareAuth(r *ghttp.Request) {
    if r.Session.Get("uid").IsNil() {
        r.Response.WriteStatusExit(401) // 内部含 Exit:终止链路
    }
    r.Middleware.Next() // 放行到下一中间件/业务处理器
}

// 日志:Next 前后分别计时,体现洋葱模型
func MiddlewareLog(r *ghttp.Request) {
    start := gtime.TimestampMilli()
    r.Middleware.Next()
    g.Log().Debug(r.Context(), "耗时ms", gtime.TimestampMilli()-start)
}

s.Use(MiddlewareLog, MiddlewareAuth) // 先注册先执行

常见追问 / 记忆点

  • 追问:r.Exit() 与不调 Next 有何区别?→ 两者都会终止后续执行;Exit 语义更“硬”,直接终止整个处理流程(当前函数后续代码也不再执行),实践常用 WriteStatusExit 组合。
  • 追问:中间件里如何拿到 Handler 的返回值?→ Next 之后通过 r.GetHandlerResponse() 读取(统一返回中间件的原理)。
  • 记忆点:洋葱 A→B→handler→B→A;Next 放行、Exit 终断;老资料里写作 r.Next(),与 v2 的 r.Middleware.Next() 语义一致(以所用版本 API 为准)。
笔记加载中…