Laravel的throttle中间件需显式注册命名策略(如RateLimiter::for('api', ...))才生效,且默认仅对api路由组启用;web路由中直接使用throttle:60,1通常静默失效或报错,必须确保缓存驱动为Redis并正确配置认证中间件顺序。

Laravel 的 throttle 中间件不是“写上就生效”的开关,它必须配合显式注册的命名策略才能真正起作用,且默认只对 api 路由组启用——在 web 路由里直接加 throttle:60,1 通常静默失效或报错。
基础用法:匿名限流(适合单条路由)
可直接在路由定义中使用,语法为 throttle:最大请求数,时间窗口(分钟):
-
throttle:60,1表示每分钟最多 60 次请求 -
throttle:100,0.5表示每 30 秒最多 100 次(支持小数,单位始终是分钟) -
throttle:1000,60表示每小时最多 1000 次(注意不是throttle:1000,1)
⚠️ 这种写法仅适用于单个路由,且底层依赖缓存驱动(如 Redis)。若用 array 或 file 驱动,多进程下计数器会失效,且不报错。
正确定义命名策略(推荐方式)
核心动作是在 app/Providers/RouteServiceProvider.php 的 configureRateLimiting() 方法中注册策略:
- 策略名必须与中间件参数一致,例如路由写
throttle:api,就必须有RateLimiter::for('api', ...) - 使用
by()明确限流维度,推荐写法:$request->user()?->id ?: $request->ip(),避免未登录用户触发空指针 - 时间单位只有
perMinute()、perHour()、perDay(),不支持原生秒级限流
示例:
use Illuminate\Cache\RateLimiting\Limit;use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(100)->by($request->user()?->id ?: $request->ip());
});
按用户角色或身份差异化限流
不能靠中间件参数硬编码,必须在策略闭包中动态判断:
- 检查用户角色:
$request->user()?->isVip()或$request->user()?->role - 确保
by()返回值稳定一致,否则同个用户可能被算成多个桶 - 若用 API Token,建议哈希处理:
hash_hmac('sha256', $token, config('app.key'))再截断
示例(VIP 用户 200 次/分钟,普通用户 60 次):
RateLimiter::for('role_based', function (Request $request) {$user = $request->user();
if ($user && $user->isVip()) {
return Limit::perMinute(200)->by($user->id);
}
return Limit::perMinute(60)->by($user?->id ?: $request->ip());
});
关键注意事项
-
认证中间件顺序很重要:若需按用户 ID 限流,
auth:sanctum或auth:api必须放在throttle前面,否则$request->user()取不到值 -
API 路由默认无 Session:不要手动加
StartSession,会破坏无状态性;应通过Authorization头提取 token 并重写resolveRequestSignature() -
缓存驱动必须为 Redis 或 database:本地开发用
array驱动会导致限流完全失效,上线前务必验证:php artisan tinker→Cache::store('redis')->increment('test') -
throttle 不控制出向请求:它只限制客户端访问你的接口频率,无法约束你自己的代码循环调用第三方 API —— 这类场景需用
Cache::add()、Redis 原子计数或封装限流 HTTP 客户端


















