概述
官方限流组件webman限流器,支持注解限流。支持apcu、redis、memory驱动。
文档:https://www.workerman.net/doc/webman/components/rate-limiter.html
接口限流器
参考如下代码
class IndexController
{
/**
* @param Request $request
* @return Response
*/
public function sendSms(Request $request): Response
{
$mobile = $request->get('mobile', '1388888888');
Limiter::check($mobile, 5, 24*60*60, '每个手机号一天最多5条短信');
return response_json('短信发送成功');
}
}
成功响应
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"message": "短信发送成功",
"data": []
}
异常响应
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
每个手机号一天最多5条短信
可以看出,限流器会抛出异常,返回的响应信息就是异常的message。并不是我们想要的统一的响应格式。
这里我们使用异常插件:https://www.workerman.net/plugin/16 接管框架的默认异常处理,保证响应格式统一。
修改配置文件config/exception.php
return [
// 这里配置异常处理类
'' => \Tinywan\ExceptionHandler\Handler::class,
];
再次请求接口,可以看到异常信息已经被统一处理了。
HTTP/1.1 500 Error
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"msg": "Internal Server Error",
"data": {}
}
但是还不是我们想要的限流异常信息,我们想要的HTTP状态码是429,响应信息是每个手机号一天最多5条短信。而这里是500,对应的错误信息是Internal Server Error。
接着继续改造代码。通过try-catch捕获异常,然后返回自定义的响应信息。
use Tinywan\ExceptionHandler\Exception\TooManyRequestsHttpException;
class IndexController
{
/**
* @param Request $request
* @return Response
* @throws TooManyRequestsHttpException
*/
public function sendSms(Request $request): Response
{
$mobile = $request->get('mobile', '1388888888');
try {
Limiter::check($mobile, 5, 24*60*60, '每个手机号一天最多5条短信');
} catch (\Throwable $throwable) {
throw new TooManyRequestsHttpException($throwable->getMessage());
}
return response_json('短信发送成功');
}
}
再次请求接口,可以看到是我们想要的结果信息了。HTTP状态码是429,响应信息是每个手机号一天最多5条短信。
HTTP/1.1 429 Too Many Requests
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"msg": "每个手机号一天最多5条短信",
"data": {}
}
注解限流器
注解限流器使用起来更加简单,只需要在控制器方法上添加注解即可。
use Webman\RateLimiter\Annotation\RateLimiter;
class IndexController
{
/**
* @param Request $request
* @return Response
*/
#[RateLimiter(3, 60, [IndexController::class, 'getMobile'], '每个手机号一天最多5条短信!')]
public function sendSms(Request $request): Response
{
return response_json('短信发送成功');
}
/**
* @desc 自定义key,获取手机号,必须是静态方法
* @return string
*/
public static function getMobile(): string
{
return request()->get('mobile','1388888888');
}
}
请求接口,可以看到异常信息已经被统一处理了。
但不是我们想要的限流异常信息,我们想要的HTTP状态码是429,响应信息是每个手机号一天最多5条短信。而这里是500,对应的错误信息是Internal Server Error。
HTTP/1.1 500 Error
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"msg": "Internal Server Error",
"data": {}
}
继续改造代码。通过自定义异常类限流器的异常,然后返回自定义的响应信息。
这里修改注解的第五个参数,指定异常类为自定义的异常类 Tinywan\ExceptionHandler\Exception\TooManyRequestsHttpException:class
/**
* @param Request $request
* @return Response
*/
#[RateLimiter(3, 60, [IndexController::class, 'getMobile'], '每个手机号一天最多5条短信!', TooManyRequestsHttpException::class)]
public function sendSms(Request $request): Response
{
return response_json('短信发送成功');
}
再次请求接口,可以看到是我们想要的结果信息了。HTTP状态码是429,响应信息是每个手机号一天最多5条短信。
HTTP/1.1 429 Too Many Requests
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"msg": "每个手机号一天最多5条短信",
"data": {}
}