handle()方法必须返回think\Response实例;TP6起禁止返回null/string/array或使用echo/exit,否则请求静默中断;TP8强制要求实现MiddlewareInterface接口且声明返回类型为\think\Response,参数也须严格类型提示。

handle() 方法必须返回 think\Response 实例
TP6 起,中间件的 handle() 方法不再接受任意返回值;漏掉 return、返回 null、string、array 或直接 echo,请求会静默中断——页面白屏或接口无响应,且框架不报错。
根本原因是:框架内部将 handle() 的返回值当作 HTTP 响应体处理,只有 think\Response 实例才具备 send()、header() 等响应能力。
- 放行请求:必须写
return $next($request); - 拦截并响应:用
return json([...]);、return redirect(...);、return view(...);等,它们底层都返回think\Response子类实例 - 绝对禁止:
echo、die、exit、return 'xxx';、return ['code'=>401];
TP8 强制声明返回类型为 \think\Response
TP8 要求所有中间件类实现 think\contract\MiddlewareInterface,且 handle() 方法签名必须带明确返回类型声明。不加会触发 PHP 严格模式报错(declare(strict_types=1) 已强制启用)。
正确写法示例(app/middleware/Auth.php):
立即学习“PHP免费学习笔记(深入)”;
namespace app\middleware;
use think\Request;
use think\Response;
use think\contract\MiddlewareInterface;
class Auth implements MiddlewareInterface
{
public function handle(Request $request, \Closure $next): Response
{
if (!session('user_id')) {
return json(['code' => 401, 'msg' => '未登录']);
}
return $next($request);
}
}
- 参数类型也建议显式声明:
Request $request,避免传入非 Request 对象时运行时出错 - 若使用 PHP 8.1+,还可配合空安全调用(如
$request->param()?->get('id')),但中间件中通常无需 - 返回类型不能写成
Response|void或省略——TP8 不接受
为什么返回 json() 却不报错?
因为 json() 是 ThinkPHP 提供的助手函数,它内部实际返回的是 think\Response 实例(具体是 think\response\Json 类对象)。同理,redirect() 返回 think\response\Redirect,view() 返回 think\response\View —— 它们都是 think\Response 的子类。
常见误判点:
-
return ['code'=>200];❌ —— 这只是数组,不是Response实例 -
return response()->json([...]);✅ —— TP6/8 都支持,等价于json() -
return new Response(...);⚠️ —— 可行但不推荐,缺少内容协商和自动编码逻辑
自定义中间件传参时,handle() 参数顺序不能错
当通过路由注册传参,例如 ->middleware(Auth::class, 'admin'),框架会把第三个参数('admin')作为额外参数注入 handle() 方法。此时签名必须严格匹配:
public function handle(Request $request, \Closure $next, string $role): Response
否则 PHP 会因参数数量不匹配而报 ArgumentCountError。注意:
- 第三个及之后的参数必须有类型声明(TP8 强制)
- 参数名可以不同(如
$permission),但位置和类型必须与路由注册时传入的值一致 - 如果没传参却写了第三个形参,运行时必报错;反之,传了参但没声明形参,参数会被丢弃
handle() 的类型声明不是可选项,而是执行链路的契约起点。哪怕只改一个字符(比如把 Response 写成 response),在 TP8 下都会导致整个中间件失效且无提示——这点比异常处理器更隐蔽。



















