nimbly / throttler
一个与框架无关的速率限制器。
Requires
- php: >=7.3 || ^8.0
Requires (Dev)
- ext-apcu: *
- ext-pdo: *
- ext-sqlite3: *
- php-coveralls/php-coveralls: ^2.1
- phpunit/phpunit: ^9
- predis/predis: ^1.1
- vimeo/psalm: ^4.0
Suggests
- ext-PDO: Use a database as the Throttler storage engine.
- ext-apcu: Use APCU as the Throttler storage engine.
- predis/predis: Use Redis as the Throttler storage engine.
This package is auto-updated.
Last update: 2024-09-15 06:34:11 UTC
README
一个与框架无关的请求速率限制器。
描述
Throttler可以在任何您喜欢的数据点上实施速率限制:IP地址、用户ID、API密钥或任何您可以访问的唯一标识信息。
安装
composer require nimbly/throttler
用法
存储适配器
您需要一个地方来跟踪点击计数器 - 缓存、数据库或任何其他。创建一个存储适配器实例并将其传递给Throttler。有关适配器的完整列表,请参阅下面的可用存储适配器部分。
$storageAdapter = new Throttler\Adapters\Redis( new Predis\Client('tcp://localhost:6379') );
Throttler
通过传递存储适配器实例来实例化Throttler。
$throttler = new Throttler($storageAdapter);
构造函数选项
您可以将键值对选项数组作为构造函数的第二个参数传递。
$throttler = new Throttler($storageAdapter, ['key' => 'value']);
支持选项
- prefix 应用到所有键和传递给存储适配器的前缀。默认为Throttler\。
方法
hit(string $id, int $limit, int $decay) : boolean
记录在速率限制器上的点击,增加速率限制计数器。在成功时返回true,在失败时返回false。
- id 是此请求源的唯一ID。此值可以是任何您想要的字符串:IP地址、用户ID等。
- limit 是在由 decay 定义的时间段内允许的总请求数。
- decay 是允许的时间段(以秒为单位)。
此示例允许每个IP地址在60秒时间段内允许120个请求。
if( $throttler->hit($request->ipAddress(), 120, 60) === false ){ throw new TooManyRequestsHttpException(60, 'Slow it down man!'); }
check(string $id) : int
检查(但不增加)给定ID的当前速率限制计数器。
if( $throttler->check($request->user->id) >= $warningThreshold ){ $response = $response->withHeader("X-Rate-Limit", "Warning"); }
中间件
将速率限制器添加到您的中间件(您正在使用中间件,对吧?)
class ThrottleRequest implements SomeMiddlewareLibrary { public function handle(Request $request, $next) { $storageAdapter = new Throttler\Adapters\Redis( new Predis\Client('tcp://localhost:6379') ); $throttler = new Throttler($storageAdapter); if( $throttler->hit($request->ipAddress(), 120, 60) === false ){ throw new TooManyRequestsHttpException(60, 'Slow it down man!'); } return $next($request); } }
可用存储适配器
以下列表提供了“开箱即用”的存储适配器
Redis
需要通过Predis库,该库可在predis/predis上找到。
$redisAdapter = new Throttler\Adapters\Redis( new Predis\Client("tcp://localhost:6379") ); $throttler = new Throttler($redisAdapter);
数据库
数据库适配器可以使用任何PDO兼容数据库来持久化速率限制器数据。只需将此表添加到您的数据库
CREATE TABLE throttler ( key VARCHAR(64) PRIMARY KEY, hits INTEGER UNSIGNED NOT NULL DEFAULT 1, expires_at INTEGER UNSIGNED NOT NULL )
$databaseAdapter = new Throttler\Adapters\Database( new PDO("mysql:dbname=myapp;host=localhost", "username", "password") ); $throttler = new Throttler($databaseAdapter);
您还可以自定义Throttler将使用的列以及垃圾回收的机会
- table 要使用的表名。默认为throttler。
- key 键列名。列类型必须是字符串或varchar。默认为key。
- hits 点击列名。列类型必须是整数。默认为hits。
- expires_at 过期列名。列类型必须是整数(UNIX时间戳)。默认为expires_at。
- gc_chance 垃圾回收运行的百分比机会。小于1的值表示它将永远不会运行。大于99的值表示它将在每个调用时运行。默认为5。
$databaseAdapter = new Throttler\Adapters\Database( new PDO("mysql:dbname=myapp;host=localhost", "username", "password"), [ "table" => "limiter", "key" => "id", "hits" => "value", "expires_at" => "ttl", "gc_chance" => 20, ] ); $throttler = new Throttler($databaseAdapter);
APCu
APCu是一个内存中的PHP缓存,需要通过大多数Linux包管理器提供的PECL APCu库。
$apcuAdapter = new Throttler\Adapters\Apcu; $throttler = new Throttler($apcuAdapter);
内存
内存适配器仅在内存中维护其节流器,不会在HTTP或CLI请求之间持久化其数据。此适配器非常适合测试或其他特殊用例。只有当您了解自己在做什么时才使用此适配器。
$memoryAdapter = new Throttler\Adapters\Memory; $throttler = new Throttler($memoryAdapter);
自定义存储适配器
提供了一个 Throttler\StorageAdapter
接口,以便您可以创建自己的适配器,用于您想要的任何持久化引擎。它必须实现两个方法
get(string $key) : int
返回给定键的当前计数器,如果键不存在则返回0。
increment(string $key, int $decay) : int
增加给定键的计数器。如果键不存在,则必须创建它并将计数器设置为1,同时将计数器设置在 $decay 秒后过期。返回计数器值。
use Nimbly\Throttler\StorageAdapter; class MyStorageAdapter implements StorageAdapter { public function get(string $key): int { // Get $key from storage engine. } public function increment(string $key, int $decay): int { // Increment $key on storage engine and return new value. } }