Bộ giới hạn tốc độ
Bộ giới hạn tốc độ webman, hỗ trợ giới hạn bằng annotation.
Hỗ trợ driver apcu, redis và memory.
Mã nguồn
https://github.com/webman-php/limiter
Cài đặt
composer require webman/limiter
Sử dụng
<?php
namespace app\controller;
use RuntimeException;
use support\limiter\annotation\Limit;
class UserController
{
#[Limit(limit: 10)]
public function index(): string
{
// Mặc định giới hạn theo IP, cửa sổ thời gian mặc định 1 giây
return 'Tối đa 10 yêu cầu mỗi IP mỗi giây';
}
#[Limit(limit: 100, ttl: 60, key: Limit::UID)]
public function search(): string
{
// key: Limit::UID, giới hạn theo ID người dùng, yêu cầu session('user.id') không rỗng
return 'Tối đa 100 tìm kiếm mỗi người dùng mỗi 60 giây';
}
#[Limit(limit: 1, ttl: 60, key: Limit::SID, message: 'Chỉ 1 email mỗi người mỗi phút')]
public function sendMail(): string
{
// key: Limit::SID, giới hạn theo session_id
return 'Email gửi thành công';
}
#[Limit(limit: 100, ttl: 24*60*60, key: 'coupon', message: 'Phiếu giảm giá hôm nay đã hết, vui lòng thử lại ngày mai')]
#[Limit(limit: 1, ttl: 24*60*60, key: Limit::UID, message: 'Mỗi người dùng chỉ có thể nhận một phiếu mỗi ngày')]
public function coupon(): string
{
// key: 'coupon', khóa tùy chỉnh cho giới hạn toàn cục, tối đa 100 phiếu mỗi ngày
// Cũng giới hạn theo ID người dùng, mỗi người dùng một phiếu mỗi ngày
return 'Phiếu giảm giá gửi thành công';
}
#[Limit(limit: 5, ttl: 24*60*60, key: [UserController::class, 'getMobile'], message: 'Tối đa 5 SMS mỗi số mỗi ngày')]
public function sendSms2(): string
{
// Khi key là biến: [lớp, phương_thức_tĩnh], vd [UserController::class, 'getMobile'] dùng giá trị trả về của UserController::getMobile() làm khóa
return 'SMS gửi thành công';
}
/**
* Khóa tùy chỉnh, lấy số điện thoại, phải là phương thức tĩnh
* @return string
*/
public static function getMobile(): string
{
return request()->get('mobile');
}
#[Limit(limit: 1, ttl: 10, key: Limit::IP, message: 'Tốc độ bị giới hạn', exception: RuntimeException::class)]
public function testException(): string
{
// Ngoại lệ mặc định khi vượt quá: support\limiter\RateLimitException, thay đổi được qua tham số exception
return 'ok';
}
}
Ghi chú
- Sử dụng thuật toán cửa sổ cố định
- Cửa sổ thời gian ttl mặc định: 1 giây
- Đặt cửa sổ qua ttl, vd
ttl:60cho 60 giây - Chiều giới hạn mặc định: IP (mặc định
127.0.0.1không giới hạn, xem cấu hình bên dưới) - Tích hợp: giới hạn IP, UID (yêu cầu
session('user.id')không rỗng), SID (theosession_id) - Khi dùng proxy nginx, truyền header
X-Forwarded-Forcho giới hạn IP, xem proxy nginx - Kích hoạt
support\limiter\RateLimitExceptionkhi vượt quá, lớp ngoại lệ tùy chỉnh quaexception:xx - Thông báo lỗi mặc định khi vượt quá:
Too Many Requests, thông báo tùy chỉnh quamessage:xx - Thông báo lỗi mặc định cũng sửa được qua đa ngôn ngữ, tham khảo 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
API
Đôi khi nhà phát triển muốn gọi bộ giới hạn trực tiếp trong mã, xem ví dụ sau:
<?php
namespace app\controller;
use RuntimeException;
use support\limiter\Limiter;
class UserController {
public function sendSms(string $mobile): string
{
// mobile được dùng làm khóa ở đây
Limiter::check($mobile, 5, 24*60*60, 'Tối đa 5 SMS mỗi số mỗi ngày');
return 'SMS gửi thành công';
}
}
Cấu hình
config/plugin/webman/limiter/app.php
<?php
use support\limiter\RateLimitException;
return [
'enable' => true,
'driver' => 'auto', // auto, apcu, memory, redis
'stores' => [
'redis' => [
'connection' => 'default',
]
],
// Các IP này không bị giới hạn (chỉ có hiệu lực khi key là Limit::IP)
'ip_whitelist' => [
'127.0.0.1',
],
'exception' => RateLimitException::class
];
- enable: Bật giới hạn tốc độ
- driver: Một trong
auto,apcu,memory,redis;autotự động chọn giữaapcu(ưu tiên) vàmemory - stores: Cấu hình Redis,
connectiontương ứng với khóa trongconfig/redis.php - ip_whitelist: Các IP trong whitelist không bị giới hạn (chỉ có hiệu lực khi key là
Limit::IP)
Chọn driver
memory
-
Giới thiệu
Không cần cài đặt extension, hiệu năng tốt nhất. -
Hạn chế
Giới hạn chỉ có hiệu lực với tiến trình hiện tại, không chia sẻ dữ liệu giữa các tiến trình, không hỗ trợ giới hạn cluster. -
Trường hợp sử dụng
Môi trường phát triển Windows; nghiệp vụ không cần giới hạn chặt; phòng thủ tấn công CC.
apcu
- Cài đặt extension
Cần extension apcu, cấu hình php.ini:
apc.enabled=1
apc.enable_cli=1
Vị trí php.ini bằng lệnh php --ini
-
Giới thiệu
Hiệu năng rất tốt, hỗ trợ chia sẻ đa tiến trình. -
Hạn chế
Không hỗ trợ cluster -
Trường hợp sử dụng
Mọi môi trường phát triển; giới hạn máy đơn production; cluster không cần giới hạn chặt; phòng thủ tấn công CC.
redis
- Phụ thuộc
Cần extension redis và component Redis, cài đặt:
composer require -W webman/redis illuminate/events
-
Giới thiệu
Hiệu năng thấp hơn apcu, hỗ trợ giới hạn chính xác máy đơn và cluster -
Trường hợp sử dụng
Môi trường phát triển; máy đơn production; môi trường cluster