laravel中间件是路由安全与逻辑解耦的实际防线,核心用于权限控制、登录校验、请求过滤和日志记录;auth中间件不可直接用于api路由因其默认依赖session的web guard,api应使用auth:sanctum或auth:api并确保token头正确;role中间件需校验用户存在并用explode+contains支持多角色or判断;日志中间件须在$next()后计算耗时并交由log::info异步写入;throttle限流依赖缓存驱动(如redis),键含ip与路由签名,ttl为参数二×60秒;本地file缓存易因文件锁导致限流不准,上线须切redis。

Laravel中间件最常用于权限控制、登录校验、请求过滤和日志记录这四类场景,不是“可有可无的装饰”,而是路由安全与逻辑解耦的实际防线。
auth 中间件为什么不能直接用在 API 路由上?
因为 auth 默认走的是 web guard(依赖 session),而 API 请求通常无 Cookie、不维持会话。直接套用会导致始终跳转登录页或报 302,而非返回 JSON 错误。
- API 场景应改用
auth:sanctum或auth:api,并在config/auth.php中确认对应 guard 的 driver 和 provider 配置正确 - 若用 Laravel Sanctum,需确保请求携带有效的
Authorization: Bearer {token}头,且前端已设置withCredentials: false - 常见错误现象:
419 Page Expired(误配 web guard)、Unauthenticated(token 过期或 header 缺失)、302 Found(被重定向到 login)
role:admin,editor 这种带参数的中间件怎么写才不漏权限?
参数传递本身简单,但容易在角色判断逻辑里漏掉“多角色 OR 关系”或忽略空用户场景。
-
handle()方法必须显式检查$request->user()是否存在,否则未登录时调用hasRole()会抛Call to a member function hasRole() on null - 参数接收要匹配数量:定义为
handle($request, $next, $roles),路由中写middleware('role:admin,editor'),Laravel 会自动把字符串按逗号拆成数组传入 - 推荐用
Str::of($roles)->explode(',')->contains(...)或in_array()做判断,避免硬编码if ($role === 'admin' || $role === 'editor')—— 后者无法支持多参数动态扩展
日志中间件为什么总记不到响应时间?
因为只在请求进入时打点,没在响应返回后读取耗时,或者用了同步写文件导致阻塞主线程。
- 必须在
$next($request)之后获取响应,再计算耗时,例如:$start = microtime(true); $response = $next($request); $duration = round((microtime(true) - $start) * 1000); - 别在中间件里直接
file_put_contents()写日志——高并发下易锁死;应交由 Laravel 日志通道(如Log::info())异步处理 - 注意:如果中间件注册在全局
$middleware数组,它会记录所有请求(包括 favicon.ico、/storage/* 等),建议改用路由级中间件或加路径白名单判断
throttle:60,1 是怎么算出“每分钟最多 60 次”的?
这个计数不是靠 PHP 进程内变量,而是依赖缓存驱动(默认是 file 或 redis),底层用的是 Laravel 的 RateLimiter 服务,键名含 IP + 路由签名。
- 参数
60,1表示“60 次 / 1 分钟”,单位固定为分钟;写成120,2效果等同,但不推荐——解析逻辑只认第二个值为“分钟数” - 若用
redis驱动,限流键类似rate_limit:ip:192.168.1.100:dashboard,TTL 就是第二个参数 × 60 秒 - 容易踩的坑:本地开发用
file缓存时,多个 PHP-FPM 进程可能因文件锁竞争导致限流不准;上线务必切到redis
中间件真正难的不是写 handle 方法,而是理清它在整个洋葱模型里的执行顺序、何时该用 terminate、以及参数和上下文在 pipeline 中如何流转——这些细节一旦错位,问题就藏得深、复现难。










