Laravel限流需显式注册策略,throttle中间件仅是外壳;未注册策略、缓存驱动错误或key不匹配均致静默失效。

直接说结论:Laravel 的限流不是“加个中间件就完事”,throttle 中间件本身只是壳,真正起作用的是你用 RateLimiter::for() 显式注册的策略;没注册策略、缓存驱动配错、或 key 生成逻辑不匹配,都会导致限流静默失效。
throttle:60,1 在 API 路由里不生效?检查三件事
这不是 bug,是默认行为。API 路由组(routes/api.php)默认不启用 session,而原生 ThrottleRequests 在未登录时 fallback 到 $request->ip(),但若你走 CDN 或 NAT,所有请求都共享一个 IP,限流就形同虚设。
- 确认
CACHE_DRIVER是redis或memcached—— 用array驱动时,多进程下计数器完全不可靠 - 别在
web路由里测试throttle,它默认不在web组中注册;想用必须手动加到$middlewareGroups['web']并确保缓存可用 - 检查是否误用了
throttle:60,1,by=id:未登录用户调用$request->user()->id会抛Call to a member function id() on null,应写成$request->user()?->id ?: $request->ip()
按设备指纹或 API Key 限流,必须重写 key 逻辑
用 IP 或用户 ID 限流太粗,尤其对 App、小程序、SaaS 多租户场景。关键不是换中间件,而是让 by() 返回稳定、唯一、无特殊字符的字符串。
- 在
App\Providers\RouteServiceProvider::configureRateLimiting()中注册策略,例如:RateLimiter::for('api-by-device', function (Request $request) {<br> return Limit::perMinute(30)->by($request->header('X-Device-ID') ?: $request->ip());<br>}); -
by()返回值不能含空格、冒号、斜杠;建议加str_slug()或urlencode()处理原始 header 值 - 别在策略闭包里做耗时操作(如查 DB),否则每次请求都拖慢整个限流判断
自定义中间件绕过 session 依赖,专用于 API
如果你需要更底层控制(比如从 Bearer Token 解析用户、合并多个标识为 key、或统一返回 JSON 429),不要改 vendor,而是继承 ThrottleRequests 并覆盖关键方法。
- 新建中间件:
php artisan make:middleware ApiThrottleRequests - 重写
resolveRequestSignature(),优先取$request->bearerToken(),fallback 到$request->ip(),避免 session - 重写
buildResponse(),返回response()->json(['message' => 'Too many requests'], 429),并设置Retry-Afterheader - 注册到
app/Http/Kernel.php的$routeMiddleware,再在路由中使用:->middleware('api.throttle:10,1')
调试 TooManyRequestsHttpException 的真实原因
线上突然大量 429,大概率不是阈值设低了,而是 key 冲突或缓存堆积。别只看日志里的异常,要查背后的状态。
- 用
redis-cli查限流 key:执行keys "throttle:*"看是否有大量过期未清理的 key(如throttle:ip:192.168.1.1) - 临时在策略闭包里加日志:
Log::debug('rate limit key', ['key' => $request->bearerToken() ?: $request->ip()]); - 用
php artisan tinker手动验证:Cache::get('throttle:'.md5('your-key'))看当前计数 - 注意:Laravel 不支持
perSecond(),最小单位是分钟;想实现秒级,得用 Redis Lua 脚本手动控制
最常被忽略的一点:命名策略(如 throttle:api)和匿名策略(如 throttle:60,1)底层用的缓存 key 格式不同,混用会导致策略不生效却无报错。选一种风格,坚持到底。


















