官方限流組件的兩種異常正確處理方式
概述
官方限流組件webman限流器,支持注解限流。支持apcu、redis、memory驅(qū)動。
文檔: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, '每個手機(jī)號一天最多5條短信');
return response_json('短信發(fā)送成功');
}
}
成功響應(yīng)
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"message": "短信發(fā)送成功",
"data": []
}
異常響應(yīng)
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
每個手機(jī)號一天最多5條短信
可以看出,限流器會拋出異常,返回的響應(yīng)信息就是異常的message。并不是我們想要的統(tǒng)一的響應(yīng)格式。
這里我們使用異常插件:https://www.workerman.net/plugin/16 接管框架的默認(rèn)異常處理,保證響應(yīng)格式統(tǒng)一。
修改配置文件config/exception.php
return [
// 這里配置異常處理類
'' => \Tinywan\ExceptionHandler\Handler::class,
];
再次請求接口,可以看到異常信息已經(jīng)被統(tǒng)一處理了。
HTTP/1.1 500 Error
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"msg": "Internal Server Error",
"data": {}
}
但是還不是我們想要的限流異常信息,我們想要的HTTP狀態(tài)碼是429,響應(yīng)信息是每個手機(jī)號一天最多5條短信。而這里是500,對應(yīng)的錯誤信息是Internal Server Error。
接著繼續(xù)改造代碼。通過try-catch捕獲異常,然后返回自定義的響應(yīng)信息。
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, '每個手機(jī)號一天最多5條短信');
} catch (\Throwable $throwable) {
throw new TooManyRequestsHttpException($throwable->getMessage());
}
return response_json('短信發(fā)送成功');
}
}
再次請求接口,可以看到是我們想要的結(jié)果信息了。HTTP狀態(tài)碼是429,響應(yīng)信息是每個手機(jī)號一天最多5條短信。
HTTP/1.1 429 Too Many Requests
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"msg": "每個手機(jī)號一天最多5條短信",
"data": {}
}
注解限流器
注解限流器使用起來更加簡單,只需要在控制器方法上添加注解即可。
use Webman\RateLimiter\Annotation\RateLimiter;
class IndexController
{
/**
* @param Request $request
* @return Response
*/
#[RateLimiter(3, 60, [IndexController::class, 'getMobile'], '每個手機(jī)號一天最多5條短信!')]
public function sendSms(Request $request): Response
{
return response_json('短信發(fā)送成功');
}
/**
* @desc 自定義key,獲取手機(jī)號,必須是靜態(tài)方法
* @return string
*/
public static function getMobile(): string
{
return request()->get('mobile','1388888888');
}
}
請求接口,可以看到異常信息已經(jīng)被統(tǒng)一處理了。
但不是我們想要的限流異常信息,我們想要的HTTP狀態(tài)碼是429,響應(yīng)信息是每個手機(jī)號一天最多5條短信。而這里是500,對應(yīng)的錯誤信息是Internal Server Error。
HTTP/1.1 500 Error
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"msg": "Internal Server Error",
"data": {}
}
繼續(xù)改造代碼。通過自定義異常類限流器的異常,然后返回自定義的響應(yīng)信息。
這里修改注解的第五個參數(shù),指定異常類為自定義的異常類 Tinywan\ExceptionHandler\Exception\TooManyRequestsHttpException:class
/**
* @param Request $request
* @return Response
*/
#[RateLimiter(3, 60, [IndexController::class, 'getMobile'], '每個手機(jī)號一天最多5條短信!', TooManyRequestsHttpException::class)]
public function sendSms(Request $request): Response
{
return response_json('短信發(fā)送成功');
}
再次請求接口,可以看到是我們想要的結(jié)果信息了。HTTP狀態(tài)碼是429,響應(yīng)信息是每個手機(jī)號一天最多5條短信。
HTTP/1.1 429 Too Many Requests
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"msg": "每個手機(jī)號一天最多5條短信",
"data": {}
}