直接用 Laravel 自带的 throttle 中间件就够了,除非有特殊计数逻辑;它基于缓存驱动(推荐 Redis),支持每分钟 60 次等灵活配置,但需确保 CACHE_DRIVER=redis 且配置生效,否则高并发下会漏限流。

限流中间件该用 throttle 还是自己写?
直接用 Laravel 自带的 throttle 中间件就够了,除非你有特殊计数逻辑(比如按用户角色分级限流、跨服务共享令牌桶)。它底层基于缓存驱动,支持 Redis、Memcached 和 file,生产环境配 Redis 就能扛住常规接口压测。
常见错误是只在路由里加 throttle:60,1 却没确认缓存驱动是否生效——如果 CACHE_DRIVER=file,高并发下会漏限流;redis 才是唯一靠谱选择。
-
throttle:60,1表示每分钟最多 60 次请求 -
throttle:10,1,by=ip显式按 IP 限流(默认就是 ip,但显式写更安全) -
throttle:5,1,by=id可改用Auth::id()或自定义键,需配合自定义中间件
怎么让限流按登录用户而不是 IP?
原生 throttle 不支持动态 key,得自己写中间件。核心是重写 resolveRequestSignature 方法,把 Auth::id() 塞进限流 key。
执行 php artisan make:middleware UserThrottle,然后在 handle 方法里调用父类的限流逻辑,但提前替换 key:
public function handle($request, Closure $next)
{
if (! $request->user()) {
return response('Unauthorized', 401);
}
<pre class="brush:php;toolbar:false;">// 强制使用 user_id 作为限流标识
$this->limiter->attempt(
'user_'.$request->user()->id,
10, // 每分钟 10 次
function () use ($request) {
return $request;
}
);
return $next($request);}
注意:这个写法绕过了 Laravel 的自动 key 构建,所以必须手动调用 attempt 并传入完整 key 字符串;别漏掉前缀(如 user_),否则不同用户的 key 可能冲突。
Redis 配置不生效?检查这三个地方
限流失败十次有九次是缓存没走对。不是 Laravel 版本问题,而是配置链路断了。
- 确认
.env里CACHE_DRIVER=redis且REDIS_HOST可连(用redis-cli -h xxx ping验证) - 检查
config/cache.php中stores.redis.connection是否和config/database.php的redis.default对得上 - 运行
php artisan config:clear && php artisan cache:clear,Laravel 会缓存 config,改了 .env 不清缓存等于白改
如果用了 Horizon 或其他队列服务,它们可能独占 Redis DB,导致限流 key 写到错的 database —— 在 config/database.php 里给 redis.default.database 指定一个独立 DB 号(比如 2),避免干扰。
限流响应被前端忽略?加个明确 header
Laravel 默认返回 429 状态码,但不带 X-RateLimit-Limit 和 X-RateLimit-Remaining 这类 header,前端没法做友好提示或自动退避。
自己写的中间件里可以补上:
$response = $next($request);
$response->headers->set('X-RateLimit-Limit', 10);
$response->headers->set('X-RateLimit-Remaining', max(0, 10 - $this->limiter->attempts($key)));
return $response;但更稳妥的是复用框架的响应构造逻辑:在中间件里捕获 ThrottleRequestsException,再用 ResponseFactory 生成带 header 的响应。否则容易漏掉重试时间(Retry-After)这类关键字段。
真正难的不是写逻辑,是让所有服务节点共享同一套 Redis 连接配置,并确保 key 命名空间不撞车——比如 API v1 和 v2 用同一套限流规则时,key 里最好带上版本前缀。


















