限流器
webman限流器,支持注解限流。
支持apcu、redis、memory驅動。
源碼地址
https://github.com/webman-php/rate-limiter
安裝
composer require webman/rate-limiter
使用
<?php
namespace app\controller;
use RuntimeException;
use Webman\RateLimiter\Annotation\RateLimiter;
class UserController
{
#[RateLimiter(limit: 10)]
public function index(): string
{
// 默認為IP限流,默認單位時間為1秒
return '每個ip每秒最多10個請求';
}
#[RateLimiter(limit: 100, ttl: 60, key: RateLimiter::UID)]
public function search(): string
{
// key: RateLimiter::UID,以用戶ID為維度進行限流,要求session('user.id')不為空
return '每個用戶60秒最多100次搜索';
}
#[RateLimiter(limit: 1, ttl: 60, key: RateLimiter::SID, message: '每人每分鐘只能發(fā)1次郵件')]
public function sendMail(): string
{
// key: RateLimiter::SID,以session_id為維度進行限流
return '郵件發(fā)送成功';
}
#[RateLimiter(limit: 100, ttl: 24*60*60, key: 'coupon', message: '今天的優(yōu)惠券已經(jīng)發(fā)完,請明天再來')]
#[RateLimiter(limit: 1, ttl: 24*60*60, key: RateLimiter::UID, message: '每個用戶每天只能領取一次優(yōu)惠券')]
public function coupon(): string
{
// key: 'coupon', 這里coupon為自定義key,也就是全局以coupon為key進行限流,每天最多發(fā)100張優(yōu)惠券
// 同時以用戶ID為維度進行限流,每個用戶每天只能領取一次優(yōu)惠券
return '優(yōu)惠券發(fā)送成功';
}
#[RateLimiter(limit: 5, ttl: 24*60*60, key: [UserController::class, 'getMobile'], message: '每個手機號一天最多5條短信')]
public function sendSms2(): string
{
// 當key為變量時,可以使用[類, 靜態(tài)方法]的方式獲取key,例如[UserController::class, 'getMobile']會調用UserController的getMobile()方法的返回值為key
return '短信發(fā)送成功';
}
/**
* 自定義key,獲取手機號,必須是靜態(tài)方法
* @return string
*/
public static function getMobile(): string
{
return request()->get('mobile');
}
#[RateLimiter(limit: 1, ttl: 10, key: RateLimiter::IP, message: '頻率受限', exception: RuntimeException::class)]
public function testException(): string
{
// 超限默認異常為Webman\RateLimiter\RateLimitException,可以通過exception參數(shù)更改
return 'ok';
}
}
說明
- 默認單位時間間隔為1秒鐘
- 可以通過ttl設置單位時間間隔,例如
ttl:60
為60秒 - 默認限流維度為IP限流(默認
127.0.0.1
不限流,參見下面配置部分) - 內置IP限流、UID限流(要求
session('user.id')
不為空),SID限流(根據(jù)session_id
限流) - 如果使用了nginx代理,IP限流時需要傳遞
X-Forwarded-For
頭,參見nginx代理 - 當超限時會觸發(fā)
Webman\RateLimiter\RateLimitException
異常,可通過exception:xx
來自定義異常類 - 超限觸發(fā)異常時,錯誤信息默認為
Too Many Requests
,可通過message:xx
自定義錯誤信息 - 默認錯誤信息也可通過多語言來修改,Linux參考以下命令
composer require symfony/translation mkdir resource/translations/zh_CN/ -p echo "<?php return [ 'Too Many Requests' => '請求頻率受限' ];" > resource/translations/zh_CN/messages.php php start.php restart
接口
有時候開發(fā)者想直接在代碼中調用限流器,參考如下代碼
<?php
namespace app\controller;
use RuntimeException;
use Webman\RateLimiter\Limiter;
class UserController {
public function sendSms(string $mobile): string
{
// 這里mobile作為key
Limiter::check($mobile, 5, 24*60*60, '每個手機號一天最多5條短信');
return '短信發(fā)送成功';
}
}
配置
config/plugin/webman/rate-limiter/app.php
<?php
return [
'enable' => true,
'driver' => 'auto', // auto, apcu, memory, redis
'stores' => [
'redis' => [
'connection' => 'default',
]
],
// 這些ip的請求不做頻率限制(只有在key為 RateLimiter::IP 時有效)
'ip_whitelist' => [
'127.0.0.1',
],
];
- enable: 是否開啟限流
- driver:
auto
apcu
memory
redis
中的一個值,使用auto
時會自動在apcu
和memory
中選一個值 - stores:
redis
配置,connection
對應config/redis.php
中對應的key
- ip_whitelist: 白名單的ip不會被限流(只在key為
RateLimiter::IP
時有效)
driver選擇
memory
-
介紹
無需安裝任何擴展,性能最好。 -
使用限制
限流只對當前進程有效,多個進程間不共享限流數(shù)據(jù),同時也不支持集群限流。 -
適用場景
windows開發(fā)環(huán)境;不需要嚴格限流的業(yè)務;抵御CC攻擊時。
apcu
-
安裝擴展
需要安裝apcu擴展,并且php.ini中設置apc.enabled=1 apc.enable_cli=1
如果不知道php.ini位置,可以通過命令
php --ini
尋找php.ini的位置 -
介紹
性能略低于memory,支持多進程共享限流數(shù)據(jù)。 -
使用限制
不支持集群 -
適用場景
任何開發(fā)環(huán)境;線上單機限流場景;集群不需要嚴格限流的場景;抵御CC攻擊。
redis
-
依賴
需要安裝redis擴展,并安裝Redis組件,安裝命令composer require -W illuminate/redis illuminate/events
-
介紹
性能低于apcu,支持單機也支持集群精確限流 -
適用場景
開發(fā)環(huán)境;線上單機環(huán)境;集群環(huán)境