Laravel中间件必须放在app/Http/Middleware/目录下,命名空间为App\Http\Middleware,类需实现handle方法并返回$next($request)。

中间件类文件放哪?别手抖建错目录
Laravel 的中间件必须放在 app/Http/Middleware/ 目录下,且类名要符合 PSR-4 命名规范(首字母大写、驼峰)。如果你用 php artisan make:middleware CheckAge,它会自动创建到正确位置;但手动新建文件时,常有人丢进 app/Middleware/ 或 app/Http/ 根目录——Laravel 找不到,注册后直接报 Class "App\Http\Middleware\CheckAge" not found。
- 确认命名空间是
namespace App\Http\Middleware;,不是App\Middleware或其他变体 - 类必须实现
handle方法,且接收两个参数:$request和Closure $next - 别漏掉
return $next($request);,否则请求链中断,后续中间件和控制器全不执行
handle 方法里怎么取参数?别硬写死逻辑
中间件本身不支持像路由那样直接绑定参数(比如 {id}),但你可以通过请求对象间接获取。常见场景是权限校验、租户识别、灰度开关等,需要动态判断。
- 从路由参数取:
$request->route()->parameter('slug'),注意判空,route()可能为 null - 从查询字符串取:
$request->input('debug'),比$_GET更安全,自动过滤空格和类型转换 - 从请求头取:
$request->header('X-Forwarded-For'),适合做 IP 白名单或设备识别 - 别在
handle里做耗时操作(如 DB 查询),除非必要;高频中间件建议加缓存或提前预加载
注册中间件时 global / group / route 三层怎么选?
注册位置决定作用域,选错等于白写。全局中间件($middleware)在 app/Http/Kernel.php 的 $middleware 数组里,所有请求都过;分组中间件($middlewareGroups)如 web 或 api,只对对应路由组生效;单个路由注册最灵活,用 ->middleware(CheckAge::class)。
- 日志、CORS、信任代理这类基础设施中间件,放
$middleware - Session、CSRF、验证用户登录状态的,必须放
web组,否则 API 路由会意外触发 session 启动 - 自定义权限中间件(如
CanEditPost)推荐用路由级注册,避免污染无关请求 - 如果中间件依赖服务容器绑定(比如注入了
UserService),确保构造函数参数能被自动解析,否则注册时报Target [App\Services\UserService] is not instantiable
中间件里抛异常怎么处理?别让 500 掩盖业务意图
中间件里 throw 新异常(比如 throw new HttpResponseException(response()->json(['error' => 'Forbidden'], 403));)是常见做法,但 Laravel 默认会把所有未捕获异常转成 500,掩盖你本意的 403/401 状态码。
- 推荐用
abort(403, 'You cannot edit this post'),它会走 Laravel 的异常渲染流程,保留状态码和响应格式 - 如果要用自定义异常类,记得继承
Illuminate\Auth\AuthenticationException或Illuminate\Foundation\Http\Exceptions\MaintenanceModeException这类已注册处理器的异常 - 别在中间件里 return view(),这会绕过后续中间件和控制器,且破坏 RESTful 响应一致性;前端拿不到标准 JSON 错误结构
- 测试时用
withoutMiddleware()在单元测试中跳过中间件,否则 mock 太重,容易误判逻辑问题
中间件的执行顺序、参数传递方式、异常传播路径,这些地方没有魔法,但每一步都卡在框架启动和请求生命周期的关键节点上。写错一个分号可能不报错,但漏掉一次 return $next($request) 就会让整个请求静默失败——这种问题最难 debug。









