Laravel特定路由限流问题:自定义中间件计数无法自动重置
解决验证邮件路由独立限流问题
问题根源
你使用的自定义中间件存在缓存过期设置错误:Cache::increment 的第三个参数并非过期时间(TTL),导致首次创建缓存时未设置过期规则,计数永久留存,最终触发永久限制。
方案一:修复自定义中间件
修改中间件代码,确保缓存键在创建时正确设置过期时间:
public function handle(Request $request, Closure $next) { $throttle = 5; // 60秒内允许5次请求 $ttl = 60; // 过期时间60秒 $key = sprintf('throttle_CustomValidateEmail:%s:%s', $request->ip(), $request->path()); $currentCount = Cache::get($key, 0); if ($currentCount >= $throttle) { return abort(429, '请求过于频繁,请稍后再试'); } // 更新计数并设置过期时间,每次请求重置窗口有效期 Cache::put($key, $currentCount + 1, $ttl); return $next($request); }
如果希望限流窗口从第一次请求开始固定计算(而非每次请求重置),可调整缓存逻辑:
if (!Cache::has($key)) { Cache::put($key, 1, $ttl); } else { Cache::increment($key); }
方案二:使用Laravel自带限流中间件(推荐)
无需自定义中间件,通过扩展Laravel原生throttle中间件,为验证邮件路由生成独立限流键,避免占用全局限流额度:
1. 创建自定义限流中间件
<?php namespace App\Http\Middleware; use Illuminate\Routing\Middleware\ThrottleRequests; class ThrottleVerificationEmails extends ThrottleRequests { /** * 生成独立限流键,与全局路由额度隔离 */ protected function resolveRequestKey($request) { // 若用户已登录,可替换为用户ID避免同IP多用户冲突:$request->user()?->id ?? $request->ip() return 'throttle:verify-email:' . $request->ip(); } }
2. 注册中间件
在app/Http/Kernel.php的$routeMiddleware数组中添加:
protected $routeMiddleware = [ // ... 'throttle.verify-email' => \App\Http\Middleware\ThrottleVerificationEmails::class, ];
3. 路由中使用
Route::post('send-verification-email', [VerificationController::class, 'send']) ->middleware('throttle.verify-email:5,1');
参数5,1表示:60秒内允许5次请求(格式为请求次数,分钟数)。
补充说明
- 若用户已登录,建议将用户ID加入限流键,避免同一IP下多用户互相影响
- 可自定义429响应的提示信息,提升用户体验
内容的提问来源于stack exchange,提问作者Deadman
相关产品推荐
相关产品推荐

