pudongping / hyperf-throttle-requests
A rate limiter implemented for Hyperf framework.
Installs: 1 384
Dependents: 1
Suggesters: 0
Security: 0
Stars: 2
Watchers: 1
Forks: 2
Open Issues: 0
Requires
- php: >=8.1
- hyperf/di: ~3.1.0
- hyperf/http-server: ~3.1.0
- hyperf/redis: ~3.1.0
- nesbot/carbon: ^2.0
- psr/container: ^1.0|^2.0
- psr/http-message: ^1.0|^2.0
README
运行环境
- php >= 8.1
- composer
- hyperf ~3.1.0
分支或者标签
分支
- 2.2: For hyperf 2.2
- 3.0: For hyperf ~3.0
- 3.1: For hyperf ~3.1
标签
- 1.0.x: For hyperf 2.2
- 2.0.x: For hyperf 3.0
- 3.0.x: For hyperf 3.1
安装
composer require pudongping/hyperf-throttle-requests:^3.0 -vvv
配置
发布配置
在你自己的项目根目录下,执行以下命令
php bin/hyperf.php vendor:publish pudongping/hyperf-throttle-requests
配置说明
使用
该组件提供了以下 3 种调用方式:
第一种:使用注解 Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests
该组件提供 Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests
注解,作用于类、类方法。
配置作用优先级为:类方法上的注解配置 > 类上的注解配置 > config/autoload/hyperf-throttle-requests.php
> 注解默认配置
注意:只有使用注解调用时,才会使用
config/autoload/hyperf-throttle-requests.php
配置文件中的配置项。
使用注解 Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests
作用于类上,示例:
<?php /** * * * Created by PhpStorm * User: Alex * Date: 2023-06-21 11:36 */ declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\AutoController; use Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests; #[AutoController(prefix: "throttle-requests")] #[ThrottleRequests] class ThrottleRequestsController { public function t1() { return [ 'name' => 'alex' ]; } public function t2() { return [ 'name' => 'harry' ]; } }
当提供 key
参数,且 key
参数的值为一个标量(不会变化的值)时,则该限流器同时作用于含有等值 key
上。举个例子来说:在以下代码中
Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests
注解作用于类上,也就意味着当访问 /throttle-requests/t1
路由
和 /throttle-requests/t2
路由时,共享相同的配置信息,由于此时的 key
参数的值为一个标量,也就意味着此时的现象是:在 15 秒内,当访问
/throttle-requests/t1
路由和 /throttle-requests/t2
路由时,总共只允许访问 5 次。
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\AutoController; use Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests; #[AutoController(prefix: "throttle-requests")] #[ThrottleRequests(key: "test-throttle", maxAttempts: 5, decaySeconds: 15, prefix: "TR:")] class ThrottleRequestsController { public function t1() { return [ 'name' => 'alex' ]; } public function t2() { return [ 'name' => 'harry' ]; } }
使用注解 Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests
作用于类方法上,示例:
以下示例代码和以上示例代码,均为同样的效果。
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\AutoController; use Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests; #[AutoController(prefix: "throttle-requests")] class ThrottleRequestsController { #[ThrottleRequests(key: "test-throttle", maxAttempts: 5, decaySeconds: 15, prefix: "TR:")] public function t1() { return [ 'name' => 'alex' ]; } #[ThrottleRequests(key: "test-throttle", maxAttempts: 5, decaySeconds: 15, prefix: "TR:")] public function t2() { return [ 'name' => 'harry' ]; } }
第二种:使用 throttle_requests(string $rateLimits = '30,60', string $prefix = '', string $key = '', mixed $generateKeyCallable = [], mixed $tooManyAttemptsCallback = [])
助手函数
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\AutoController; #[AutoController(prefix: "throttle-requests")] class ThrottleRequestsController { public function t1() { throttle_requests(rateLimits: "5,15"); return [ 'name' => 'alex' ]; } }
第三种:直接调用 Pudongping\HyperfThrottleRequests\Handler\ThrottleRequestsHandler@handle()
方法
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\AutoController; use Pudongping\HyperfThrottleRequests\Handler\ThrottleRequestsHandler; use Hyperf\Context\ApplicationContext; #[AutoController(prefix: "throttle-requests")] class ThrottleRequestsController { public function t2() { ApplicationContext::getContainer()->get(ThrottleRequestsHandler::class)->handle(5, 15); return [ 'name' => 'harry' ]; } }
关于计数器的 key
本质上,当传入的 key
参数不为空字符串时,则以传入的 key
为主。当 key
为空字符串,但是 generateKeyCallable
为一个可调用的回调函数时,
则以回调函数的返回值作为计数器的 key。否则默认为 sha1(当前路由地址路径 . '|' . 当前客户端 IP 地址)
作为 key。
其实质来说,
generateKeyCallable
回调函数就是去生成key
参数的值,这是为了方便使用者根据自己的需求动态的去生成计数器的键名。比如说:可能 当用户登录之后,会加上 user_id 作为计数器的 key。
使用自定义 key 示例:
App\Controller\ThrottleRequestsController.php
文件中
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\AutoController; use Pudongping\HyperfThrottleRequests\Handler\ThrottleRequestsHandler; use Hyperf\Context\ApplicationContext; use Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests; use App\Helper\ThrottleRequestsHelper; use Hyperf\HttpServer\Contract\RequestInterface; #[AutoController(prefix: "throttle-requests")] class ThrottleRequestsController { public function __construct(protected RequestInterface $request) { } #[ThrottleRequests(generateKeyCallable: [ThrottleRequestsHelper::class, "generateKeyCallable"])] public function t1() { return [ 'name' => 'alex' ]; } public function t2() { ApplicationContext::getContainer() ->get(ThrottleRequestsHandler::class) ->handle( 5, 15, generateKeyCallable: [$this, 'generateKeyCallable'] ); return [ 'name' => 'harry' ]; } public function generateKeyCallable() { return 'alex_' . $this->request->url(); } }
触发访问频率限制
当限流被触发时,默认会抛出 Pudongping\HyperfThrottleRequests\Exception\ThrottleRequestsException
异常,可以通过捕获异常
或者配置 tooManyAttemptsCallback
限流回调处理。例如:
App\Controller\ThrottleRequestsController.php
文件中
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\AutoController; use Pudongping\HyperfThrottleRequests\Handler\ThrottleRequestsHandler; use Hyperf\Context\ApplicationContext; use Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests; use App\Helper\ThrottleRequestsHelper; #[AutoController(prefix: "throttle-requests")] class ThrottleRequestsController { #[ThrottleRequests(tooManyAttemptsCallback: [ThrottleRequestsHelper::class, 'tooManyAttemptsCallback'])] public function t1() { return [ 'name' => 'alex' ]; } public function t2() { ApplicationContext::getContainer() ->get(ThrottleRequestsHandler::class) ->handle( 5, 15, tooManyAttemptsCallback: function () { var_dump('请求过于频繁'); throw new \RuntimeException('请求过于频繁', 429); } ); return [ 'name' => 'harry' ]; } }
App\Helper\ThrottleRequestsHelper.php
文件中
<?php declare(strict_types=1); namespace App\Helper; use Hyperf\HttpServer\Contract\RequestInterface; use Hyperf\Context\ApplicationContext; class ThrottleRequestsHelper { public function __construct(protected RequestInterface $request) { } public static function generateKeyCallable() { $request = ApplicationContext::getContainer()->get(RequestInterface::class); return $request->getUri()->getPath(); } public static function tooManyAttemptsCallback() { var_dump('Too Many Attempts.'); throw new \RuntimeException('请求过于频繁', 429); } }