当前位置: 首页 > 后端技术 > PHP

hyperf框架完美的异常处理(连载)

时间:2023-03-29 19:35:49 PHP

转发自WhiteWolfStack:查看原文上一课我们封装了统一响应的方法。敲过代码的朋友可能会发现一个明显的问题。对于业务逻辑我们经常写在Service里面,比如:App\Service\IndexService(自己创建)如下:'datainfo'];}}这时候我们需要用到IndexController::info方法,通过try/catch进行捕获和处理,如下:useApp\Service\IndexService;useHyperf\Di\Annotation\Inject;useHyperf\HttpServer\Annotation\AutoController;#[AutoController]classIndexControllerextendsAbstractController{/***@varIndexService*/#[Inject]public$indexService;publicfunctioninfo(){try{return$this->response->success($this->indexService->info($id));}catch(\Throwable$e){return$this->response->fail(500,$e->getMessage());}}}其中,Index服务注入是通过#[Inject]注解来注入@var注解声明的属性类型对象。DependencyInjectionReference[https://hyperf.wiki/3.0/#/zh-...](https://hyperf.wiki/3.0/#/zh-...)好像解决了主动抛异常的问题,但也带来了新的问题。比如每个方法都要用try/catch来捕获,这无疑增加了很多麻烦。hyperf提供了一个异常处理器(ExceptionHandler),专门处理业务流程中没有捕获到的异常。需要在config/autoload/exceptions.php文件中配置异常处理程序。hyperf框架默认配置了两个ErrorHandles,如下:],],];我们找到Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler的isValid方法,会发现它是针对Hyperf\HttpMessage\Exception\HttpException的异常处理的。publicfunctionisValid(Throwable$throwable):bool{return$throwableinstanceofHttpException;}处理方法(参考Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::handle)也很简单,看下面3行代码publicfunctionhandle(Throwable$throwable,ResponseInterface$response){//①$this->logger->debug($this->formatter->format($throwable));//②$this->stopPropagation();//③return$response->withStatus($throwable->getStatusCode())->withBody(newSwooleStream($throwable->getMessage()));}①、控制台输出异常信息②、异常处理到此结束,不再有冒泡投递的风险③,http直接响应http状态码并输出异常信息curl请求一个不存在的路由来测试?~curl-Ihttp://127.0.0.1:9501/index/info222HTTP/1.1404NotFoundServer:swoole-http-serverConnection:keep-aliveContent-Type:text/htmlDate:Tue,01Nov202208:40:10GMTHyperf\HttpServer\Exception\Handler\HttpExceptionHandler是hyperf的源代码文件,我们不容易修改,先直接阻塞,等待AppExceptionHandler中统一处理。现在我们只保留一个App\Exception\Handler,看AppExceptionHandler::handle方法,它也向控制台输出错误信息、异常堆栈、InternalServerError。这对我们来说毫无意义。在重写AppExceptionHandler之前,先创建一个业务异常类,然后使用这个类主动抛出异常。app/Exception目录新增BusinessException,继承Hyperf\Server\Exception\ServerException,代码如下:logger=$container->get(LoggerFactory::class)->get('exception');$this->response=$response;}publicfunctionhandle(Throwable$throwable,ResponseInterface$response){$formatter=ApplicationContext::getContainer()->get(FormatterInterface::class);//业务异常类if($throwableinstanceofBusinessException){return$this->response->fail($throwable->getCode(),$throwable->getMessage());}//HttpExceptionif($throwableinstanceofHttpException){return$this->response->fail($throwable->getStatusCode(),$throwable->getMessage());}$this->logger->error($formatter->format($throwable));返回$this->response->fail(500,env('APP_ENV')=='dev'?$throwable->getMessage():'ServerError');}公共函数isValid(Throwable$thr欠款):bool{returntrue;}}isValid方法返回true,表示接收并处理所有异常。在处理方法handle中,除了App\Exception\BusinessException、Hyperf\HttpMessage\Exception\HttpException异常,其他的都是通过App\Components的\Response::fail方法处理并记录所有异常到日志文件。现在IndexController::info方法重写如下:publicfunctioninfo(){$id=(int)$this->request->input('id',0);return$this->response->success($this->indexService->info($id));}IndexService::info改写如下:useApp\Exception\BusinessException;classIndexService{publicfunctioninfo(int$id){if($id<=0){thrownewBusinessException("idinvalid");}return['info'=>'datainfo'];}}curl测试:?~curlhttp://127.0.0.1:9501/index/info?id=0{"code":500,"message":"idinvalid"}%?~curlhttp://127.0.0.1:9501/index/info222{"code":404,"message":"NotFound"}%至此,我们的框架已经成型,但我们的论坛已经准备好向全世界的用户开放。如果像上面这样抛出一个“idisinvalid”,老外认为是乱码。在下一节中,我们使框架支持国际化。

最新推荐
猜你喜欢