ThinkPHP中间件需显式调用return $next($request)驱动执行链,注册仅限三处(全局/路由/控制器),handle()必须返回Response实例,$request->post()因php://input单次读取特性易为空,参数传递须在注册时声明。
$next($request) 驱动,不是自动调用ThinkPHP 的中间件不靠“注册即生效”的魔法,而是依赖显式调用 $next($request) 把请求往下传。框架内核用管道模式(Pipeline)把所有中间件串成洋葱圈,$next 就是剥开一层后通往下一层的唯一函数。漏掉 return $next($request),等于在中途剪断水管——后续中间件、控制器、视图全被跳过,浏览器收不到响应,日志里也难见痕迹。
handle() 方法必须返回 thinkResponse 实例,不能只调用 $next($request) 而不 return
if 分支返回 redirect(),else 分支必须跟 return $next($request)
$next($request) 之后,操作其返回的 $response 对象,例如 $response->header('X-Trace', 'done')
写了类文件 ≠ 框架认得它。ThinkPHP 只从三个位置读取中间件配置,缺一不可:
app/middleware.php(TP6/TP8 单应用)或 config/middleware.php(多应用),返回数组,元素必须是完整类名字符串,如 'appmiddlewareAuthCheck' 或 appmiddlewareAuthCheck::class
route/app.php 中链式调用 middleware(),支持类名、别名(需提前映射)、数组,例如 Route::get('api/user', 'Api/User')->middleware(['auth', 'throttle'])
$middleware 中声明,或构造函数中调用 $this->middleware(),可带条件过滤,如 ['CheckRole' => ['only' => ['delete']]]
常见错误:类文件放在 app/middleware/auth/AuthCheck.php —— 框架默认不扫描子目录;命名空间写成 appmiddlewareauthAuthCheck 但文件实际在根 middleware 目录下。
$request->post() 为空?多半是前面中间件已读空输入流PHP 的 php://input 流只能读一次。$request->post() 和 $request->input() 底层都依赖它。一旦任一中间件(包括框架内置的 ValidatePostSize)调用了它们,后续再调就返回空数组——这不是 Bug,是 PHP 特性。
立即学习“PHP免费学习笔记(深入)”;
$request->param(),它由框架缓存解析结果,多次调用无副作用post()/input()
SessionInit 中间件通常靠后执行,需确认执行顺序想往 handle() 里传额外参数(比如角色白名单),不能靠构造函数注入,必须在注册时以数组形式声明:
->middleware(['check_role' => ['admin', 'editor']])
protected $middleware = [appmiddlewareCheckRole::class => ['admin', 'editor']]
handle() 签名要匹配:public function handle($request, Closure $next, $role1, $role2)
没按注册格式传参,框架不会自动解包,参数会丢失;参数个数与注册数组长度不一致,会导致 ArgumentCountError。
中间件真正起效的临界点很薄:注册位置、返回语句、流读取时机、参数写法,任意一环出错都会静默失效。线上问题排查时,优先盯住这四块,比翻源码快得多。