限制每分钟发送到应用程序的请求数通常是必要的,以防止试图使您的服务器饱和或暴力验证表单的攻击。这就是为什么 Laravel 带有速率限制机制的原因,我们将在这里学习使用它。
Laravel 有两种实现速率限制的方法:
- 使用速率限制器中间件:在到达控制器之前限制传入的 HTTP 请求
- 使用速率限制抽象:在控制器级别与速率限制器进行更精细的交互
在本文中,我们将只看到第一种实现方法,即使用throttle
中间件设置一个简单的限速系统。
开始使用
throttle
中间件用于保护路由免受过多 HTTP 请求的过度接收,并在达到限制后限制它们。
首先,您应该首先定义应用程序所需的速率限制器配置。为此,请转到方法App\Providers\RouteServiceProvider
定义中的类configureRateLimiting()
。
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\RateLimiter;
class RouteServiceProvider extends ServiceProvider
{
// ...
public function boot(): void
{
$this->configureRateLimiting();
// ...
}
/**
* Configure the rate limiters for the application.
*/
protected function configureRateLimiting(): void
{
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(1000);
});
}
}
在上面的示例中,我们定义了一个称为速率限制器的速率限制器global
,它将对其关联的路由的访问限制为每分钟 1000 个请求。
您可以使用所需的名称创建任意数量的配置。例如,我们可以想象有global
, downloads
,chat
来根据路线自定义限制。
定义了速率限制器后,您可以使用throttle
中间件将它们应用到要限制速率的路由,如下所示:
<?php
Route::middleware(['throttle:global'])->group(function () {
Route::get('/products', [ProductController::class, 'index']);
Route::get('/products/{product}', [ProductController::class, 'show']);
Route::post('/products', [ProductController::class, 'store']);
});
Route::middleware(['throttle:downloads'])->group(function () {
Route::get('/reports/{report}/download', [ReportController::class, 'download']);
Route::get('/albums/{album}/download', [AlbumController::class, 'download']);
});
如您所见,您只需要传递一个字符串,其中包含throttle:
您定义的速率限制器的名称。
对于这些路由,如果达到速率限制,应用程序将返回“429 — Too Many Requests”响应,而不是提供预期的响应。
⚠️注意!api
如果您的应用程序有一个使用中间件组的 API ,则默认情况下,中间件将应用于您的类属性中throttles:api
定义的这些路由。因此,您必须定义一个称为速率限制器或将其从组中删除。$middlewareGroups['api']
App\Http\Kernel
api
分段速率限制
到目前为止,正如我们之前示例中所定义的,我们的速率限制器没有区分用户。他们阻止了应用程序每分钟收到的来自所有用户的请求总数。
这不是很有效,因为它可以阻止那些没有试图淹没应用程序的用户。所以最好设置每个用户的请求限制。by
为此,您可以在构建速率限制器时使用该方法:
<?php
RateLimiter::for('downloads', function (Request $request) {
// 速率将用户限制为每分钟 10 个请求
return Limit::perMinute(10)->by($request->user()->id);
});
因此,每个用户每分钟只能访问关联的路由 10 次,然后才会受到限制。
如果我们想将速率限制应用于不一定需要身份验证的路由怎么办?事实上,$request->user()
可能是null
这样,使用 IP 地址也是一个好主意。
<?php
RateLimiter::for('global', function (Request $request) {
return $request->user()
? Limit::perMinute(100)->by($request->user()->id)
: Limit::perMinute(20)->by($request->ip());
});
经过身份验证的用户现在每分钟可以发送 100 个请求,而未经身份验证的用户每分钟只能发送20 个请求(他们的速率与他们的 IP 地址相关联)。
看起来还不错!我们现在有一个有效的配置速率限制器。将throttle
中间件与RateLimiter
外观一起使用非常棒且令人愉快。
但是,这RateLimiter
不仅意味着与throttle
中间件一起使用,您还可以在控制器中以更高级的方式使用它。我邀请您查阅文档以了解更多信息。