Laravel 仅尝试一次后,速率限制器错误地限制了访问

Laravel Rate Limiter Limits Access Wrongly After Only One Attempt

我正在与 Laravel 5.8 合作,我想设置一个速率限制器来限制每分钟访问路由以及 IP 地址。

所以我将其添加到 RouteServiceProvider.php:

protected function configureRateLimiting()
    {
        RateLimiter::for('limited', function (Request $request) {
            return [
                Limit::perMinute(500),
                Limit::perMinute(20)->by($request->ip()),
            ];
        });
    }

然后应用到路线:

Route::get("/", "StaticPages\HomeController@show")->middleware('throttle:limited')->name('home');

因此它应该在从同一 IP 地址尝试 500 次或 20 次后限制访问。

但现在的问题是它仅在一次尝试后显示 429 请求过多

不知道为什么只试了一次就限制访问

那么这里出了什么问题?

如何将基于 IP 地址的限制正确设置为每分钟 20 和 500 个请求?

我认为你需要编写代码 [return response('Custom response...', 429); ] 在函数中。

RateLimiter::for('limited', function (Request $request) {
    
    return Limit::perMinute(1000)->response(function () {
    return response('Custom response...', 429);

});

有关 rate-limiting 的更多信息:

https://laravel.com/docs/8.x/routing#rate-limiting

我认为您在 Laravel 中尝试实施请求速率限制器时阅读了错误的文档。 “named throttle”仅从版本 8 开始引入。它在版本 5.8 上不可用,请参阅特定版本的 laravel documentations

如果您通过以下方式声明油门:

 Route::get("/", "StaticPages\HomeController@show")->middleware('throttle:20,1')->name('home');

您可以在 returning HTTP Header 上看到第一个请求后说 x-ratelimit-remaining 19。因此,速率限制按预期工作。但是,如果你输入 throttle:limited 它将无法理解它的含义,returns -1 表示 x-ratelimit-remaining - 这就是为什么你可以打开页面一次并且 return 后续请求的 HTTP 错误 429。

如果你对我的解释还有疑问,请在configureRateLimiting的开头加上一个die(),这样:

protected function configureRateLimiting()
{
    die();
    RateLimiter::for('limited', function (Request $request) {
        return [
            Limit::perMinute(500),
            Limit::perMinute(20)->by($request->ip()),
        ];
    });
}

如果该特定功能实际上由 Laravel 执行,您的应用程序应该在响应任何请求之前停止工作。如果不是,那就 运行 就好了。

此时,您只有 2 个选项来实施您的速率限制器策略:1) 实施您自己的速率限制器中间件; 2) 将您的 Laravel 至少更新到版本 8。

仅供参考,在Laravel文档页面的右上角,您可以设置要阅读的文档版本。

如果您使用的是 api,请尝试转至 app\Http\Kernel.php 并进行配置: 'throttle:[max_rate],[per_minutes]'

'api' => [
            'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

或尝试覆盖函数

protected function resolveRequestSignature($request)
    {
        if ($user = $request->user()) {
            return sha1($user->getAuthIdentifier());
        }

        if ($route = $request->route()) {
            return sha1($route->getDomain().'|'.$request->ip());
        }

    throw new RuntimeException('Unable to generate the request signature. Route unavailable.');
}

仔细看看这两个 if 语句。如果用户在场,则节流键基于他们的用户标识符。如果用户不存在,则标识符包括 $request->ip()。来自不同 IP 地址的请求进入不同的限制桶。

我同意@Bagus Tesa。 Laravel 5.8 throttle 中间件不接受除 max_rate 和 per_minutes 之外的参数。命名速率限制是在 Laravel 8 中引入的,并且仅在 >= Laravel 8 版本中可用。您可以实施自己的速率限制中间件或升级到 Laravel 8 以实现预期功能。

参考:https://laravel.com/docs/5.8/routing#rate-limiting