前置中间件必须调用 return $next($request) 否则请求卡死;依赖如 session、user 需按 encryptcookies→startsession→verifycsrftoken→auth 顺序注册;全局中间件作用于所有请求,路由级仅限指定路由。

前置中间件(BeforeMiddleware)必须在控制器执行前完成逻辑判断,并且要确保调用 $next($request) 向下游传递请求;漏掉这行,控制器收不到请求,页面空白或超时,还不会报错。
为什么 $next($request) 不能漏?
这是前置中间件最常踩的坑:不调用 $next($request),请求就卡死在当前中间件,后续所有逻辑(包括控制器、视图、响应生成)全部跳过。Laravel 不会抛异常,只返回空响应或连接超时,排查时容易误判为网络或路由问题。
- 正确写法:
return $next($request);—— 必须有return,否则 PHP 返回null,Laravel 内核无法处理 - 提前终止时,必须手动返回一个
Response实例,比如return redirect('/login');或return response()->json(['error' => 'Forbidden'], 403); - 不要在
$next($request)后再写业务逻辑(那是后置中间件的事),前置中间件只做「放行 or 拦截」决策
handle() 中依赖注入和请求检查怎么写才安全?
前置中间件的 handle() 方法接收 $request 和 $next,但你可能需要用户、session、token 等上下文。注意这些依赖的可用性有严格顺序约束:
-
EncryptCookies必须在StartSession之前 —— 否则 session cookie 解密失败,$request->session()为空 -
StartSession必须在VerifyCsrfToken之前 —— 否则 CSRF token 读不到 session 数据,校验必失败 - 若你在自定义前置中间件里调用
$request->user(),它依赖auth中间件已运行,所以你的中间件必须注册在auth之后(即排在$middleware数组更靠后的位置)
如何验证前置中间件是否真正在控制器前执行?
最直接的办法是加日志或断点,但要注意:别只看 dd() 或 Log::info() 输出位置,得确认执行时机是否符合预期。推荐用以下方式交叉验证:
- 在中间件
handle()开头加Log::debug('before middleware start', ['uri' => $request->getRequestUri()]); - 在控制器方法第一行加同格式日志
- 查
storage/logs/laravel.log,确认时间戳顺序:中间件日志必须严格早于控制器日志 - 如果用了
dd(),注意它会中断整个响应流程,导致后续中间件和控制器完全不执行,仅适合临时调试
全局 vs 路由级前置中间件,注册位置和影响范围差异
两者都叫「前置」,但生效时机和依赖环境不同,选错位置会导致逻辑失效:
- 全局前置中间件写在
app/Http/Kernel.php的$middleware数组里 —— 对所有请求(包括 API、静态资源、甚至 OPTIONS 预检)都生效,适合加密、CORS、基础鉴权 - 路由级前置中间件注册在
$routeMiddleware,再通过Route::middleware('check.token')绑定 —— 只对指定路由起作用,适合业务强相关的校验(如会员等级、活动状态) - 别把需要 session 的逻辑放在全局中间件顶部(比如排在
EncryptCookies前),否则$request->session()一定为空,且无提示
真正难的不是写 handle(),而是理解中间件链里每个环节的输入输出边界——尤其是 $next($request) 返回的是一个完整的 Response 对象,不是控制器返回的数组或视图名。这点一旦混淆,后置逻辑和数据透传就会全盘出错。











