Laravel API 速率限制需显式配置 throttle 中间件,如 throttle:60,1;默认按 IP 限流,登录用户需确保 auth:sanctum 在 throttle 前执行;自定义策略应于 RouteServiceProvider 中定义并指定 by() 键;生产环境必须使用 Redis 缓存驱动。

直接在 Laravel 中用 throttle 中间件就能实现 API 速率限制,无需额外包。关键在于路由定义时的参数组合和自定义限流策略的时机。
如何在 API 路由中启用 throttle 中间件
Laravel 默认已为 api 路由组注册了 throttle:api,但这个策略实际是空的(Laravel 9+),必须手动配置或替换。最常用做法是显式指定中间件参数:
-
throttle:60,1表示每分钟最多 60 次请求 -
throttle:100,5表示每 5 分钟最多 100 次 - 参数顺序固定:请求数量,时间窗口(单位:分钟)
- 该中间件默认按客户端 IP 限流;如需按用户 ID 或 API token 区分,需自定义
为什么匿名用户被限流而登录用户没效果?
因为默认 throttle 实现使用 $request->ip() 作为 key 基础,对所有未认证请求一视同仁。而登录用户若走的是 api guard 且未在中间件中显式切换识别逻辑,仍可能 fallback 到 IP —— 尤其当你的认证是通过 Authorization: Bearer xxx 但未启用 EnsureTokenIsValid 类中间件时。
- 确保 API 认证中间件(如
auth:sanctum)在throttle之前执行 - 否则
Auth::id()取不到值,限流 key 退化为 IP - 正确顺序示例:
middleware(['auth:sanctum', 'throttle:30,1'])
如何按用户 ID 或 API token 限流(而非 IP)
需要重写限流 key 的生成逻辑。Laravel 允许在 app/Providers/RouteServiceProvider.php 的 configureRateLimiting 方法中注册自定义策略:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
RateLimiter::for('api_by_user', function (Request $request) {
return $request->user()
? Limit::perMinute(60)->by($request->user()->id)
: Limit::perMinute(10)->by($request->ip());
});
然后在路由中使用:middleware('throttle:api_by_user')。注意:by() 的值必须是字符串,且不能含特殊字符;若用 token,建议取 hash_hmac('sha256', $token, config('app.key')) 再截断。
常见错误:429 响应体不包含 Retry-After 或 X-RateLimit 头
这是因你用了非标准响应格式(比如全局返回 JSON 的异常处理器覆盖了 Laravel 原生 ThrottleRequests 的响应逻辑)。原生中间件会在响应头中自动添加:
-
X-RateLimit-Limit:窗口内最大请求数 -
X-RateLimit-Remaining:剩余可请求数 -
Retry-After:秒级等待时间(仅当超出时) - 若这些头缺失,检查是否在
App\Exceptions\Handler.php中误捕获了ThrottleRequestsException并返回了无头响应
真正容易被忽略的是:缓存驱动必须支持原子计数(如 Redis),否则 file 或 database 缓存在高并发下会漏限流。生产环境务必确认 CACHE_DRIVER=redis 且连接正常。










