Laravel API限流需基于Redis驱动,通过RouteServiceProvider定义按用户ID或IP区分的命名策略,并在api路由中应用throttle:api中间件;同时配置自定义429响应及暴露X-RateLimit头,确保游客与登录用户隔离计数且避免NAT误杀。

你需要为 Laravel API 接口配置稳定、可区分用户身份、能返回标准 JSON 的限流机制,避免因 session 依赖导致 throttle 中间件在 routes/api.php 中完全失效,同时防止 NAT 环境下按 IP 限流误杀大量正常用户。
确认限流失效的根本原因
打开 routes/api.php,检查目标路由是否被 api 中间件组包裹 → 查看 app/Http/Kernel.php 中 $middlewareGroups['api'] 是否包含 \Illuminate\Routing\Middleware\ThrottleRequests::class → 运行 php artisan route:middleware | grep throttle,确认 throttle 中间件注册状态 → 执行 php artisan tinker,输入 cache()->store('redis')->get('throttle:ip:127.0.0.1'),若返回 null 或报错,说明缓存驱动未生效。
【必须用 Redis 缓存驱动】 Laravel 的限流计数器依赖原子操作,array 或 file 驱动在多进程下必然失效,且 RateLimiter::remaining() 会恒定返回 -1。
启用基础 API 限流(每分钟 60 次)
编辑 app/Providers/RouteServiceProvider.php,在 configureRateLimiting() 方法内添加:
RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); });
修改 routes/api.php 中对应路由:Route::get('/status', [StatusController::class, 'check'])->middleware('throttle:api');
这一步让登录用户按 ID 单独计数,未登录用户 fallback 到 IP。注意 ?-> 是 PHP 8.0+ 空安全操作符,避免 Call to a member function id() on null 错误。
精细化区分游客与登录用户的限流策略
方法一:角色差异化配额
在 configureRateLimiting() 中替换原 api 策略:
RateLimiter::for('api', function (Request $request) { if ($request->user()?->is_premium) { return Limit::perMinute(500)->by($request->user()->id); } elseif ($request->user()) { return Limit::perMinute(100)->by($request->user()->id); } else { return Limit::perMinute(10)->by($request->ip()); } });
方法二:按请求头识别设备指纹(防 CDN/IP 共享)
新增策略 'api-by-device':
RateLimiter::for('api-by-device', function (Request $request) { $deviceId = $request->header('X-Device-ID'); return Limit::perMinute(30)->by($deviceId ?: $request->ip()); });
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
然后在特定路由启用:->middleware('throttle:api-by-device')
【X-Device-ID 值必须为纯字符串】 若含空格或斜杠,Redis key 会损坏,导致限流完全不触发。
自定义 429 响应格式并暴露关键响应头
第一步:创建中间件 php artisan make:middleware ApiThrottleResponse
第二步:在 app/Http/Middleware/ApiThrottleResponse.php 的 handle() 方法中,捕获 ThrottleRequestsException:
try { return $next($request); } catch (ThrottleRequestsException $e) { return response()->json([ 'message' => '请求过于频繁,请稍后再试', 'retry_after' => $e->getHeaders()['Retry-After'] ?? 60 ], 429) ->withHeaders([ 'X-RateLimit-Limit' => $e->getHeaders()['X-RateLimit-Limit'], 'X-RateLimit-Remaining' => $e->getHeaders()['X-RateLimit-Remaining'], 'Retry-After' => $e->getHeaders()['Retry-After'], ]); }
第三步:在 app/Http/Kernel.php 的 $middlewareGroups['api'] 中,将 \App\Http\Middleware\ApiThrottleResponse::class 放在 \Illuminate\Routing\Middleware\ThrottleRequests::class 之后。
第四步:确保 config/cors.php 中 'expose' 数组包含 ['X-RateLimit-Limit', 'X-RateLimit-Remaining', 'Retry-After'],否则前端无法读取这些头部。
验证限流是否真实生效
① 使用 curl 发起 61 次请求:for i in {1..61}; do curl -s -o /dev/null -w "%{http_code}\n" "http://localhost:8000/api/status"; done | grep "429" | wc -l
② 检查 Redis 中的限流 key:redis-cli --raw keys "throttle:*" | grep -E "(user|ip)"
③ 查看某 IP 当前剩余次数:redis-cli get "throttle:ip:127.0.0.1"
④ 登录后用不同 token 请求同一接口,确认两个用户的计数器互不干扰。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










