如何在 Laravel 中实现请求数速率限制

限制每分钟发送到应用程序的请求数通常是必要的,以防止试图使您的服务器饱和或暴力验证表单的攻击。这就是为什么 Laravel 带有速率限制机制的原因,我们将在这里学习使用它。

Laravel 有两种实现速率限制的方法:

  1. 使用速率限制器中间件:在到达控制器之前限制传入的 HTTP 请求
  2. 使用速率限制抽象:在控制器级别与速率限制器进行更精细的交互

在本文中,我们将只看到第一种实现方法,即使用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 个请求。

您可以使用所需的名称创建任意数量的配置。例如,我们可以想象有globaldownloads,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\Kernelapi

分段速率限制

到目前为止,正如我们之前示例中所定义的,我们的速率限制器没有区分用户。他们阻止了应用程序每分钟收到的来自所有用户的请求总数。

这不是很有效,因为它可以阻止那些没有试图淹没应用程序的用户。所以最好设置每个用户的请求限制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中间件一起使用,您还可以在控制器中以更高级的方式使用它。我邀请您查阅文档以了解更多信息。

庄朋龙
庄朋龙

一个爱生活的技术菜鸟

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注