Laravel怎么使用Rate Limiting限流_Laravel API访问控制教程【防护】

1次阅读

ratelimiter::attempt() 总返回 false 是因默认按用户 id 限流且需手动传唯一 key;无登录态时 auth()->id() 为 NULL 导致 key 错误,应改用 ip 或自定义 guest key。

Laravel怎么使用Rate Limiting限流_Laravel API访问控制教程【防护】

RateLimiter::attempt() 为什么总返回 false?

不是配置没生效,而是 RateLimiter::attempt() 默认只对「当前用户 ID」限流,且要求你手动传入唯一键(比如 $key),它不会自动识别 API 路由或 IP。如果你直接照搬文档里带 auth()->id() 的例子,但接口是无登录态的(如公开 API),auth()->id() 就是 null,整个 key 变成 "rate_limit:NULL"——所有请求都挤在同一个桶里,看起来像“全局限流”,实际是 key 写错了。

  • 无登录场景下,用 request()->ip()request()->header('X-forwarded-For') 构建 key,但注意反向代理要配置好 TrustedProxy
  • Key 中避免空值:写成 'rate_limit:'.($userId ?? 'guest_'.request()->ip()),别裸用 auth()->id()
  • RateLimiter::attempt() 第三个参数是「最大尝试次数」,第四个是「窗口秒数」,顺序不能错;漏传会默认为 60 秒,但前两个参数不满足时直接返回 false

api middleware 里的 throttle:60,1 和 throttle:global 有啥区别?

前者是基于路由名或控制器方法动态生成 key 的「局部限流」,后者走的是 cache()->get('throttle_global') 这种硬编码 key,基本等于摆设——laravel 官方 throttle 中间件压根没实现 global 类型,写了也白写,日志里连 key 都搜不到。

  • 想按 IP 限流:用 throttle:10,1,by=ip(Laravel 9+ 支持 by 参数)
  • 想按用户 ID(需登录):用 throttle:100,60,by=id,前提是中间件在 auth:api 之后执行
  • 自定义策略必须注册在 AppProvidersRouteServiceProvider::configureRateLimiting() 里,写在中间件参数里不会触发自定义逻辑

自定义 RateLimiter 策略里 $limiter->remaining() 返回 -1 怎么办?

说明缓存驱动没写成功,或者 key 根本没进缓存。常见原因是用了 Array 缓存驱动(开发环境默认),它不支持 TTL 和原子计数,remaining() 拿不到实时余量,一律返回 -1;另一个原因是 redis 连接失败但没报错,静默 fallback 到 array 驱动。

  • 上线前确认 CACHE_DRIVER=redis,且 REDIS_CLIENT=predisphpredis 已装好扩展
  • 检查 config/cache.phpstores.redis.connection 是否指向正确的 Redis DB
  • 临时加一行日志:Log::info('Cache driver: '.config('cache.default'));,别只信 .env

测试限流时 429 响应体为空或格式不对

Laravel 默认的 429 响应是纯文本 "Too Many Requests",前端难解析;而且如果你用了 Sanctum 或 Passport,中间件顺序错位(比如 throttleauth:sanctum 前面),未登录请求根本走不到限流逻辑——因为没认证就先被拦在 auth 中间件了。

  • 统一响应格式:在 app/Exceptions/Handler.phprender() 方法里 catch ThrottleRequestsException,return json 响应
  • 确保中间件顺序:API 路由组里把 throttle 放在 auth:api 后面,或者用无状态策略(如按 IP)绕过 auth 依赖
  • postman 测试时记得关掉「自动重定向」,否则 429 可能被当成跳转失败而掩盖真实响应头

限流真正难的不是写几行代码,而是 key 的设计粒度和缓存的一致性。IP 可伪造、Token 可复用、用户 ID 在多设备登录时会冲突——这些边界情况不会报错,只会让限流效果偏移,得靠日志里真实 key 的分布去反推。

text=ZqhQzanResources