Laravel 11路由限流通过RateLimiter门面定义命名策略、注册throttle中间件并应用到API路由实现,依赖Redis等支持原子操作的缓存驱动,需手动启用且不可硬编码参数。

Laravel 11 的路由限流器(Rate Limiter)延续了 Laravel 9+ 的设计逻辑,核心由 RateLimiter 门面 + 命名策略 + throttle 中间件组成,不再依赖硬编码参数,而是强调可读性、可维护性和多维度控制。设置接口访问频次限制的关键在于三步:定义策略、注册中间件、应用到路由。
在 RouteServiceProvider 中定义命名限流策略
打开 app/Providers/RouteServiceProvider.php,在 configureRateLimiting() 方法中使用 RateLimiter::for() 注册策略。这是 Laravel 11 推荐的唯一方式,取代了旧版直接写 throttle:60,1 的做法。
- 策略名(如
'api')需全局唯一,后续路由通过该名称引用 - 闭包必须返回
Limit实例,支持perMinute()、perHour()、perDay()(不支持原生秒级,但可用小数如perMinute(120)表示每30秒2次) -
by()决定限流维度——登录用户用$request->user()?->id,游客用$request->ip(),API Key 用户用$request->bearerToken()或自定义头
示例(区分登录用户与游客):
use Illuminate\Cache\RateLimiting\Limit;use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('api', function (Request $request) {
if ($request->user()) {
return Limit::perMinute(100)->by($request->user()->id);
}
return Limit::perMinute(10)->by($request->ip());
});
确保缓存驱动支持原子操作
Laravel 11 的限流完全依赖缓存后端的原子递增能力(如 Redis 的 INCR + EXPIRE)。若配置不当,限流会静默失效。
当代理已经知道网站路由或内容URL,并且在启动前需要有效的sitemap XML、sitemap索引或robots.txt引用时,请使用sitemap。这是一个发布构件技能,而不是爬虫或SEO平台。
- 生产环境必须使用
redis或memcached驱动;file或array驱动仅适用于本地调试,多进程下无法保证计数一致性 - 检查
.env中CACHE_DRIVER=redis,并确认REDIS_CLIENT和连接配置正确 - 若使用 Laravel Octane,还需启用
cache进程共享机制(默认已开启)
在 API 路由中显式应用 throttle:xxx
Laravel 11 不再为 api 中间件组自动启用限流,必须手动添加 throttle:xxx(xxx 为上一步定义的策略名)。
- 不要写
throttle:100,1这类硬编码,否则与RateLimiter::for()脱节,后期难以统一维护 - 推荐只对高风险或资源敏感接口单独加限流,而非整个 API 组
- 务必确保路由属于
api中间件组(含throttle所需的 session/cors 环境)
示例:
use Illuminate\Support\Facades\Route;Route::middleware(['api', 'throttle:api'])->group(function () {
Route::get('/posts', [PostController::class, 'index']);
});
自定义 429 响应格式(可选但推荐)
默认返回 HTML 页面,不符合 API 场景。可在 app/Exceptions/Handler.php 的 render() 方法中捕获 ThrottleRequestsException,统一返回 JSON:
if ($exception instanceof ThrottleRequestsException) {
return response()->json([
'message' => 'Too many requests. Please try again later.',
'retry_after' => $exception->retryAfter(),
], 429)
->header('X-RateLimit-Remaining', 0)
->header('Retry-After', $exception->retryAfter());
}


















