官方限流組件的兩種異常正確處理方式
概述
官方限流組件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": {}
}