thinkphp中间件需显式调用return $next($request)驱动执行链,注册仅限全局、路由、控制器三处,handle()必须返回response实例,$request->post()因php://input单次读取易为空,参数传递须在注册时声明。

想让ThinkPHP项目具备可插拔、可复用的请求处理能力,必须搞懂中间件机制——它不是写完类就自动生效的魔法,而是靠显式调用驱动执行链,漏掉return $next($request)整条链就断在半路,浏览器收不到响应,日志里也难见痕迹。
中间件注册:三处必填,缺一不可
写了中间件类文件 ≠ 框架认得它。ThinkPHP只从三个位置读取配置,少一个都不加载:
① 全局注册:打开app/middleware.php(TP6/TP8单应用)或config/middleware.php(多应用),返回数组,元素必须是完整类名字符串,如'app\middleware\AuthCheck'或ppmiddlewareAuthCheck::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——框架默认不扫描子目录;命名空间写成appmiddlewareuthAuthCheck但文件实际在根middleware目录下。
中间件执行:$next($request)是唯一通关钥匙
中间件执行链靠$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')。
参数传递与输入流陷阱
方法一:注册时声明参数
在路由或控制器注册中间件时,可传入参数数组,例如middleware(['log', 'throttle:100,1']),其中throttle:100,1会作为参数传入Throttle中间件的handle()方法。
方法二:通过构造函数注入依赖
在中间件类构造函数中接收服务容器绑定的对象,如public function __construct(CacheInterface $cache),框架会自动解析注入。
$request->post()为空?多半是前面中间件已读空输入流。
PHP的php://input流只能读一次。$request->post()和$request->input()底层都依赖它。一旦任一中间件(包括框架内置的ValidatePostSize)调用了它们,后续再调就返回空数组——这不是Bug,是PHP特性。
安全解法:统一改用$request->param(),它由框架缓存解析结果,多次调用无副作用。
必须读原始流时(如验签加密payload),只能在第一个执行的中间件里一次性读取。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











