laravel限流不生效主因是缓存驱动、限流键、策略注册三者未对齐:cache_driver须为redis/memcached(非array),策略名需在routeserviceprovider::configureratelimiting()中注册且与中间件参数一致,by()值须为纯字符串并避免null。

限流中间件不是加了就生效,关键在缓存驱动、限流键和策略注册三处是否对齐。
throttle:60,1 为什么线上完全不生效?
最常见原因是缓存驱动配置为 array,多进程下计数器互不可见——本地开发可能“看起来正常”,但部署到 FPM 或 Swoole 后立刻失效。
- 检查
CACHE_DRIVER环境变量是否为redis或memcached(生产必须) - 运行
php artisan tinker手动验证:Cache::store('redis')->put('test:rate', 'ok', 10),确认 Redis 连通性 - 确保
app/Http/Kernel.php的$middlewareGroups['api']中已包含\Illuminate\Routing\Middleware\ThrottleRequests::class
RateLimiter::for() 注册的策略不被路由识别?
命名策略必须在 RouteServiceProvider::configureRateLimiting() 中注册,且该方法需在 boot() 阶段被调用;直接写在 AppServiceProvider@boot 里,路由解析时还没加载,会静默忽略。
- 策略名(如
'api')必须与中间件参数完全一致:->middleware('throttle:api') -
by()返回值必须是纯字符串,不能含空格、斜杠、换行——例如$request->header('X-Device-ID')建议先str($value)->trim()->replace(['/', ' '], '_')->toString() - 若策略中用了
$request->user(),注意未登录时返回 null,by(null)会导致 key 变成throttle|,所有匿名请求共用一个计数器
TooManyRequestsHttpException 大量出现,怎么快速定位是策略问题还是流量突增?
别急着调高阈值。先确认是不是限流键太宽泛:比如用 by=auth:id,但用户 token 过期后反复重登,旧 session 的计数器还卡在 Redis 里没过期,新请求全被误杀。
- 查日志时重点看异常堆栈前的
$request->fullUrl()和$request->header('X-Forwarded-For')(尤其走 CDN 时) - 用
php artisan tinker快速验 key:Cache::get('throttle|' . $request->ip())或Cache::get('throttle|' . $user->id) - 临时加一行日志到
ThrottleRequests::handleRequest()的开头(建议用事件监听或装饰器,避免改 vendor)
如何让 VIP 用户绕过普通限流但保留基础防护?
不能靠“跳过中间件”,而要用策略内部分支控制——否则会丢失监控和审计线索。
- 在
RateLimiter::for('api')闭包里判断角色,但始终返回Limit实例,哪怕配成perMinute(9999) - 避免用
if ($user->isVip()) { return $next($request); }这类绕过逻辑,它会让限流中间件彻底不执行,后续无法统计、无法响应 429 - 若需彻底豁免某类请求(如健康检查),应在策略中提前分支:
if ($request->is('api/health')) return Limit::perMinute(1000)->by($request->ip());
真正难的不是写那几行 RateLimiter::for(),而是确保缓存能写、key 能分、策略能加载、异常能追溯——四者缺一,限流就形同虚设。











