我创建了一个与 laravel throttle 一起使用的页面访问功能。每个 ip/用户可以每 60 分钟增加一次访问计数器。 我有一个问题,无法在不同的 ID 上应用节流阀,并且节流阀每 60 分钟仅在路线上工作 1 次并且不关心 ID: (/home/visit/3 , /home/visit/4 ,.....): 每 60 分钟 1 次
路线.php:
Route::post('/home/visit/{id}',[HomeController::class,'counter_visit'])->middleware('throttle:visit');
RouteServiceProvider.php
RateLimiter::for('visit', function (Request $request) {
return $request->user()
? Limit::perHour(1)->by($request->user()->id)
: Limit::perHour(1)->by($request->ip());
});
我怎样才能像下面那样为每个 id 应用限制?
/home/visit/3 : 每 60 分钟 1 次 /home/visit/4 :每 60 分钟 1 次
感谢您的帮助
目前,您正在使用 Laravel 内置的 throttle 中间件,它限制每个用户或 IP 地址对给定路由的请求数量,而不管 ID 参数。要实现基于 ID 参数的节流,需要定义自己的自定义中间件。
这是一个示例,说明如何创建自定义中间件,根据 ID 限制请求:
php artisan make:middleware ThrottleById
打开新建的ThrottleById中间件类,修改handle()方法,加入如下代码:
使用 Illuminate\Cache\RateLimiter;
使用 Symfony\Component\HttpFoundation\Response;
使用 Illuminate\Http\Exceptions\ThrottleRequestsException;
公共函数句柄($request, Closure $next, $maxAttempts = 1, $decayMinutes = 60)
{
$limiter = app(RateLimiter::class)->for('visit_'.$request->route('id'), $maxAttempts, $decayMinutes);
if ($limiter->tooManyAttempts($request)) {
$retryAfter = $limiter->availableIn($request);
抛出新的 ThrottleRequestsException(null, $retryAfter, [
'Retry-After' => $retryAfter,
'X-RateLimit-Limit' => $maxAttempts,
'X-RateLimit-剩余'=> 0,
]);
}
$limiter->hit($request);
$response = $next($request);
$response->headers->add([
'X-RateLimit-Limit' => $maxAttempts,
'X-RateLimit-Remaining' => $limiter->retriesLeft($request),
'X-RateLimit-Reset' => $limiter->availableAt($request),
]);
return $response;
}
以上代码是Laravel内置节流中间件的实现,只是修改为使用请求的ID参数为每个ID创建唯一的缓存键。
接下来在App\Http\Kernel类中的$routeMiddleware数组中注册中间件:
protected $routeMiddleware = [ // ... 'throttle_by_id' => \App\Http\Middleware\ThrottleById::class, ];
最后,将新的中间件应用到您的路由定义中,如下所示:
Route::post('/home/visit/{id}', [HomeController::class, 'counter_visit'])->middleware('throttle_by_id');