Maison >développement back-end >Problème PHP >Comment utiliser correctement les exceptions dans l'architecture des microservices
Cet article vous présentera l'utilisation correcte des exceptions dans l'architecture des microservices. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il sera utile à tout le monde.
@Override public DataResult<List<AdsDTO>> getAds(Integer liveId) { try { List<AdsDTO> adsDTO = new ArrayList<>(); //...业务逻辑省略 DataResult.success(adsDTO); } catch (Exception e) { log.error("getAds has Exception:{}", e.getMessage(), e); DataResult.failure(ResultCode.CODE_INTERNAL_ERROR, e.getMessage()); // 将异常信息返回给服务端调用方 } return dataResult; }Souvent, j'écris simplement un try catch sans réfléchir, qu'il contienne ou non des exceptions non liées à l'exécution. Une meilleure façon consiste à utiliser aop pour intercepter tous les appels de méthodes de service, prendre en charge uniformément les exceptions et les gérer.
@Around("recordLog()") public Object record(ProceedingJoinPoint joinPoint) throws Throwable { //... 请求调用来源记录 Object result; try { result = joinPoint.proceed(joinPoint.getArgs()); } catch (Exception e) { //... 记录异常日志 DataResult<Object> res = DataResult.failure(ResultCode.CODE_INTERNAL_ERROR, e.getMessage()); result = res; } //... 返回值日志记录 return result; }Il y a un petit problème. Si les informations d'exception du service A sont renvoyées directement à l'appelant B, il peut y avoir des risques potentiels. Vous ne pouvez jamais faire confiance à l'appelant, même s'il s'agit d'un pauvre de troisième génération. paysan. Comme il n'est pas certain de la manière dont l'appelant gérera le message d'erreur, il peut être renvoyé directement au frontal en tant que json.
@Override public DataResult<List<AdsDTO>> getAds(Integer liveId) { Preconditions.checkArgument(null != liveId, "liveIds not be null"); List<AdsDTO> adsDTOS = new ArrayList<>(); //...业务逻辑省略 return DataResult.success(adsDTOS); }Nous pouvons également utiliser cette fonctionnalité pour personnaliser notre propre classe d'exception métier afin d'hériter de RuntimeException
XXServiceRuntimeException extends RuntimeExceptionPour les situations qui ne sont pas conformes à la logique métier, lancez directement XXServiceRuntimeException
@Override public DataResult<List<AdsDTO>> getAds(Integer liveId) { if (null == liveId) { throw new XXServiceRuntimeException("liveId can't be null"); } List<AdsDTO> adsDTOS = new ArrayList<>(); //...业务逻辑省略 return DataResult.success(adsDTOS); }puis aop effectue un traitement unifié et effectue les optimisations correspondantes. Pour l'approche approximative précédente, les exceptions autres que XXServiceRuntimeException et IllegalArgumentException doivent être enregistrées en interne et ne plus être exposées au monde extérieur. Cependant, vous devez vous rappeler d'enchaîner les liens distribués via requestId In. DataResult Retournez pour faciliter le dépannage.
@Around("recordLog()") public Object record(ProceedingJoinPoint joinPoint) throws Throwable { //... 请求调用来源记录 Object result; try { result = joinPoint.proceed(joinPoint.getArgs()); } catch (Exception e) { //... 记录异常日志① log.error("{}#{}, exception:{}:", clazzSimpleName, methodName, e.getClass().getSimpleName(), e); DataResult<Object> res = DataResult.failure(ResultCode.CODE_INTERNAL_ERROR); if (e instanceof XXServiceRuntimeException || e instanceof IllegalArgumentException) { res.setMessage(e.getMessage()); } result = res; } if (result instanceof DataResult) { ((DataResult) result).setRequestId(EagleEye.getTraceId()); // DMC } //... 返回值日志记录 return result; }
* and ERROR not XXServiceRuntimeException not IllegalArgumentException|SELECT COUNT(*) AS countCe qui est surveillé ici, c'est le journal des exceptions d'enregistrement du journal ①
//1. call_user_func_array //2. 反射 //3. 直接 new try { $class = new $className(); $result = $class->$methodName(); } catch (\Throwable $e) { //...略 }. Semblable à la logique architecturale ci-dessus, plus de duplication de pseudo-code, fondamentalement cohérent. Il est également possible de personnaliser votre propre classe d'exception métier pour hériter de RuntimeException, puis d'effectuer un traitement de sortie externe. Cependant, il existe un bagage historique dans PHP lors de sa conception initiale, de nombreuses exceptions d'exécution étaient générées sous forme d'erreurs de notification et d'avertissement, mais la sortie d'erreur manquait de pile d'appels, ce qui n'était pas propice au dépannage
function foo(){ return boo("xxx"); } function boo($a){ return explode($a); } foo();
Warning: explode() expects at least 2 parameters, 1 given in /Users/mengkang/Downloads/ab.php on line 8
Vous ne pouvez pas voir les paramètres spécifiques, ni la pile d'appels. Si vous utilisez set_error_handler + ErrorException, ce sera très clair.
set_error_handler(function ($severity, $message, $file, $line) { throw new ErrorException($message, 10001, $severity, $file, $line); }); function foo(){ return boo("xxx"); } function boo($a){ return explode($a); } try{ foo(); }catch(Exception $e){ echo $e->getTraceAsString(); }
La dernière information imprimée est
Fatal error: Uncaught ErrorException: explode() expects at least 2 parameters, 1 given in /Users/mengkang/Downloads/ab.php:12 Stack trace: #0 [internal function]: {closure}(2, 'explode() expec...', '/Users/mengkang...', 12, Array) #1 /Users/mengkang/Downloads/ab.php(12): explode('xxx') #2 /Users/mengkang/Downloads/ab.php(8): boo('xxx') #3 /Users/mengkang/Downloads/ab.php(15): foo() #4 {main} thrown in /Users/mengkang/Downloads/ab.php on line 12
Si vous modifiez la fonction ci-dessus
function boo(array $a){ return implode(",", $a); }
, elle ne peut pas être capturée, car l'erreur fatale PHP : Uncaught TypeError est levée, PHP7 Avec l'ajout de la
class Error implémente Throwable, il y aura Stack dans le journal des erreurs du système PHP, mais il ne peut pas être connecté en série avec l'ensemble du système métier. Ici, nous devons parler de la conception du journal à laquelle nous nous attendons. pour utiliser un traceId comme Java. Tous les journaux sont concaténés, des journaux Nginx aux journaux de niveau d'information normaux en PHP et ces Uncaught TypeErrors, de sorte que la sortie par défaut est reprise dans le journal des erreurs système et enregistrée à un endroit unifié dans le bloc de code catch. . Ensuite, modifiez-le simplement ici pourset_error_handler(function ($severity, $message, $file, $line) { throw new ErrorException($message, 10001, $severity, $file, $line); }); function foo(){ return boo("xxx"); } function boo(array $a){ return implode(",", $a); } try{ foo(); }catch(Throwable $e){ echo $e->getTraceAsString(); }
Mais set_error_handler ne peut pas gérer certaines erreurs, telles que les erreurs E_PARSE. Vous pouvez utiliser register_shutdown_function pour les gérer.
值得注意的是register_shutdown_function的用意是在脚本正常退出或显示调用exit时,执行注册的函数。
是脚本运行(run-time not parse-time)出错退出时,才能使用。如果在调用register_shutdown_function的同一文件的里面有语法错误,是无法注册的,但是我们项目一般都是分多个文件的,这样就其他文件里有语法错误,也能捕获了
register_shutdown_function(function(){ $e = error_get_last(); if ($e){ throw new \ErrorException($e["message"], 10002, E_ERROR, $e["file"], $e["line"]); } });
如果你想直接使用这些代码(PHP的)直接到项目可能会有很多坑,因为我们习惯了系统中有很多 notice 了,可以将 notice 的错误转成异常之后主动记录,但是不对外抛出异常即可。
推荐学习:php视频教程
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!