Laravel 5.6 API路由节流中间件请求次数限制异常咨询
这个问题我之前帮朋友排查过类似的情况,大概率是节流计数的逻辑没考虑到API请求的特殊场景,我给你拆解下可能的原因和对应的解决办法:
最可能的原因:OPTIONS预检请求被计入节流次数
当你在前端发起跨域API请求时,浏览器会自动发送OPTIONS预检请求来确认服务器是否允许跨域,而默认的apiThrottle中间件会把这个OPTIONS请求也计入节流次数。这样每次实际的业务请求(比如GET/POST)都会消耗2次额度(OPTIONS + 业务请求),配置的5,1(1分钟5次)就会变成实际只能发起2次业务请求(2*2=4次,第三次业务请求就会触发第5次计数)。
而Web路由的请求一般不会触发OPTIONS预检,所以能正常执行5次后才触发限制。
解决方案
1. 自定义节流中间件,忽略OPTIONS请求
我们可以继承Laravel原生的节流中间件,添加逻辑跳过OPTIONS请求的计数:
首先创建自定义中间件文件app/Http/Middleware/CustomApiThrottle.php:
<?php namespace App\Http\Middleware; use Illuminate\Routing\Middleware\ThrottleRequests; class CustomApiThrottle extends ThrottleRequests { public function handle($request, \Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '') { // 跳过OPTIONS请求的节流计数 if ($request->isMethod('OPTIONS')) { return $next($request); } return parent::handle($request, $next, $maxAttempts, $decayMinutes, $prefix); } }
然后在app/Http/Kernel.php里注册这个中间件:
protected $routeMiddleware = [ // 其他中间件... 'customApiThrottle' => \App\Http\Middleware\CustomApiThrottle::class, ];
最后在API路由中使用这个自定义中间件:
Route::middleware('customApiThrottle:5,1')->get('/posts', function () { // 返回Post JSON资源 });
2. 调整CORS中间件的执行顺序
如果你使用了CORS扩展包(比如barryvdh/laravel-cors),确保CORS中间件在节流中间件之前执行。这样OPTIONS请求会被CORS中间件直接处理并响应,不会走到节流中间件的逻辑里。
修改app/Http/Kernel.php的api中间件组:
protected $middlewareGroups = [ 'api' => [ \Barryvdh\Cors\HandleCors::class, // 放在节流中间件前面 'throttle:5,1', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], ];
3. 排查是否存在重复路由
有时候同一个API路由被重复定义(比如在api.php和其他路由文件里都有相同的URL),每次请求会匹配多个路由,导致节流计数被多次扣除。可以通过以下命令查看所有路由,检查是否有重复条目:
php artisan route:list
4. 确认缓存驱动的稳定性
如果你的缓存驱动用的是file,可能存在文件读写延迟或者锁的问题,导致节流计数不准确。可以尝试切换到redis或者database缓存驱动,看看问题是否消失。
内容的提问来源于stack exchange,提问作者Ya Basha

