放行请求必须写为return $next($request);,它是中间件链式调用的唯一出口;不调用则卡死,不return则框架收不到响应。

放行请求只有一种写法:return $next($request);,它不是可选操作,而是中间件继续向下执行的唯一出口。
为什么必须用 return $next($request); 放行
ThinkPHP 中间件的执行模型是「链式调用」:每个中间件通过 $next 闭包把控制权交给下一个。不调用 $next($request),请求就卡死在这里;不 return 它的返回值,框架收不到响应对象,会报错或静默失败。
常见错误包括:
- 写了
$next($request);但没return—— 后续中间件和控制器不会执行,且可能返回空响应 - 在条件分支里漏掉
return $next($request);—— 比如只在if里放行,else却没 return 任何 response - 误用
exit或die终止流程 —— 跳过框架响应生命周期,日志、钩子、异常处理全失效
handle() 里放行的位置决定拦截逻辑是否生效
校验类中间件(如鉴权、CSRF、IP 白名单)必须把 return $next($request); 放在最后,前面所有检查失败都应直接 return response()->deny() 或重定向。
立即学习“PHP免费学习笔记(深入)”;
例如正确写法:
public function handle($request, \Closure $next)
{
if (!$this->isLogin()) {
return redirect('login');
}
if (!$this->hasPermission($request)) {
return response('Forbidden', 403);
}
// ✅ 放行必须在所有拦截判断之后
return $next($request);
}
错误写法(提前放行导致漏检):
public function handle($request, \Closure $next)
{
return $next($request); // ❌ 这行一执行,后面逻辑永远不跑
if (!$this->isLogin()) {
return redirect('login');
}
}
跨域中间件里放行要特别注意 OPTIONS 预检
处理跨域时,OPTIONS 请求必须被立即响应并终止,不能传给 $next,否则会进控制器层再报错或 404。
关键点:
-
$request->isOptions()为 true 时,必须return response('', 204)或类似空响应 - 不能对
OPTIONS调用$next($request)—— 它没有业务意义,还可能触发后续中间件的非预期行为(比如 AuthMiddleware 尝试读 session) -
Access-Control-Allow-Origin等头必须在OPTIONS响应中设置,不能只在后续响应里加
全局中间件顺序错会导致放行失效
ThinkPHP 6.x 的 config/middleware.php 数组顺序决定执行链。如果 AuthMiddleware 放在 ParseJsonBody::class 后面,$request->post() 就是空的 —— 那你基于 POST 数据做的放行判断(比如 token 校验)就会误判为非法请求。
典型依赖关系:
-
ForceHttpsMiddleware→ 最前(不依赖 request 属性) -
ValidatePostSize::class→ 紧随其后(防大文件绕过) -
ParseJsonBody::class或VerifyCsrfToken::class→ 必须在AuthMiddleware前 -
AuthMiddleware::class和权限中间件 → 必须连续靠前 -
Logger::class→ 必须靠后(需要完整上下文)
顺序一旦错,return $next($request); 虽然语法正确,但实际放行的是一个数据不全、状态异常的请求。



















