RateLimiter 未生效主因是 throttle 中间件注册顺序错误,须置于 auth:api 后、bindings 前且仅在 $middlewareGroups['api'] 中;需自定义限流器按用户 ID 限流,并避免 Redis 故障导致 API 瘫痪。

RateLimiter 为什么没生效?检查中间件注册顺序
API 请求限流不生效,90% 是因为 throttle 中间件被放在了 auth 或 api 之外——它必须在认证之后、路由匹配之前运行,否则匿名请求会直接被拦在门外,而登录用户又可能绕过规则。
-
app/Http/Kernel.php中,确保throttle:api在auth:api之后、bindings之前 - 不要把它加到全局
$middleware,只放$middlewareGroups['api']里 - 如果用了自定义 guard(比如
sanctum),确认throttle的 key 生成逻辑能拿到用户 ID;否则默认按 IP 限流,对登录用户无效
如何按用户 ID 而非 IP 限流?重写 throttle 的 key 生成逻辑
Laravel 默认的 throttle:60,1,public 按 IP 限流,但 API 场景下更需要“每个用户每分钟最多 60 次”。这得靠自定义限流器,而不是改中间件参数。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
- 在
App\Providers\RouteServiceProvider::boot()里注册:RateLimiter::for('api_by_user', function (Request $request) { return Limit::perMinute(60)->by($request->user()?->id ?? $request->ip()); }); - 路由中使用:
->middleware('throttle:api_by_user') - 注意:若用户未登录,
$request->user()返回 null,?? $request->ip()是兜底,避免 key 变成null导致全站共享一个桶
throttle 中间件的第三个参数是干啥的?别乱设 public
像 throttle:60,1,public 这种写法里的 public,是指是否允许客户端缓存响应头(X-RateLimit-*),和“是否公开限流策略”完全无关。设成 public 可能让 CDN 或浏览器缓存限流头,导致后续请求误判。
- 绝大多数 API 不需要缓存限流头,直接用
throttle:60,1(两个参数)最安全 - 只有当你明确需要前端读取
X-RateLimit-Remaining并做 UI 提示,且确认网关/CDN 不会缓存这些头时,才考虑加第三个参数 - 如果用了 Sanctum + SPA,还开了 CORS,
public可能让浏览器预检请求(OPTIONS)也计入限额——这时应单独排除 OPTIONS
Redis 连接失败时 throttle 怎么降级?别让整个 API 瘫痪
限流器底层依赖 Redis,默认配置下一旦 Redis 不可用,throttle 会抛出 ConnectionException,导致所有 API 请求 500。这不是预期行为。
- 在
config/cache.php中为redis驱动设置'retry_after' => 0和'connect_timeout' => 1,缩短失败等待时间 - 更稳妥的是换用
cache驱动(如array或file)做临时降级,但要注意:这些驱动不支持分布式,多实例部署时失效 - 生产环境强烈建议用 Redis Sentinel 或 Cluster,并在
APP_ENV=production下禁用array缓存驱动——它不会报错,但会让限流形同虚设
redis 存用户级限流,却在本地开发用 array 驱动测试,根本测不出并发问题。

















