🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
使用tp6 自定义异常处理,将404、500等错误进行处理 render渲染方法重写: 1、如果是ajax请求,则返回对应状态,调试模式下返回堆栈 2、如果是页面请求,则返回对应错误模板页面渲染。 report报告方法重写: 1、Undefined index、offset、variable比较常见,屏蔽以不推送消息,采用原生记录即可 2、推送消息走异步,防止并发出现响应变慢。记录异常的前几个堆栈的参数,方便开发验证问题 3、推送异常,走默认原生记录,防止死循环` 1. <?php 2. /* 3.  * @Description: 应用异常处理类 4.  * @Author: KingFer 5.  * @Date: 2019-08-13 17:24:45 6.  */ 8. namespace app; 10. use app\common\helper\QueueHelper; 11. useErrorException; 12. useException; 13. useInvalidArgumentException; 14. useParseError; 15. usePDOException; 16. use think\db\exception\DataNotFoundException; 17. use think\db\exception\ModelNotFoundException; 18. use think\exception\ClassNotFoundException; 19. use think\exception\Handle; 20. use think\exception\HttpException; 21. use think\exception\HttpResponseException; 22. use think\exception\RouteNotFoundException; 23. use think\exception\ValidateException; 24. use think\Response; 25. useThrowable; 26. useTypeError; 28. classExceptionHandleextendsHandle 29. { 30. /** 31.      * 不需要记录信息(日志)的异常类列表 32.      * @var array 33.      */ 34. protected $ignoreReport =[ 35. HttpResponseException::class, 36. ValidateException::class, 37. ]; 39. protected $error_num; 40. publicfunction __construct() 41. { 42.         $this->error_num ='Y'. makeRandCode(13). date('mdHis'); 43.         parent::__construct(app()); 44. } 46. /** 47.      * Render an exception into an HTTP response. 48.      * 49.      * @access public 50.      * @param \think\Request   $request 51.      * @param Throwable $e 52.      * @return Response 53.      */ 54. publicfunction render($request,Throwable $e):Response 55. { 56. if(!$this->isIgnoreReport($e)){ 57. // 添加自定义异常处理机制 58. // 参数验证错误 59. if($e instanceofValidateException){ 60. return json($e->getError(),422); 61. } 63. // ajax请求404异常 , 不返回错误页面 64. if(($e instanceofClassNotFoundException|| $e instanceofRouteNotFoundException)&& request()->isAjax()){ 65. return json(['msg'=> env('app_debug')? $e->getMessage():'当前请求资源不存在,请稍后再试','code'=>404,'data'=>[]]); 66. } 68. //类未找到, 返回错误页面 69. if(($e instanceofClassNotFoundException|| $e instanceofRouteNotFoundException)||($e instanceofHttpException&& $e->getStatusCode()==404)){ 70. return view(root_path().'public/error/404.html',['e'=> $e],404); 71. } 73. // ajax请求500异常, 不返回错误页面 74. if(($e instanceofException|| $e instanceofPDOException|| $e instanceofHttpException|| $e instanceofInvalidArgumentException|| $e instanceofErrorException|| $e instanceofParseError|| $e instanceofTypeError)&& request()->isAjax()){ 75. return json(['msg'=> env('app_debug')? $e->getMessage():'系统异常,请稍后再试','code'=>500,'data'=> env('app_debug')? $e->getTrace():[]]); 76. } 78. // 内部异常 , 返回错误页面 79. if($e instanceofException|| $e instanceofPDOException|| $e instanceofInvalidArgumentException|| $e instanceofErrorException|| $e instanceofParseError|| $e instanceofTypeError||($e instanceofHttpException&& $e->getStatusCode()==500)){ 80. return view(root_path().'public/error/500-2.html',['e'=> $e,'error_num'=> $this->error_num],500); 81. } 82. } 83. // 其他错误交给系统处理 84. return parent::render($request, $e); 85. } 87. /** 88.      * 记录异常信息(包括日志或者其它方式记录) 89.      * 90.      * @access public 91.      * @param  Throwable $exception 92.      * @return void 93.      */ 94. publicfunction report(Throwable $e):void 95. { 96. if(!$this->isIgnoreReport($e)){ 97. if( 98.                 $e instanceofClassNotFoundException||($e instanceofHttpException&& $e->getStatusCode()==404) 99. || stripos($e->getMessage(),"Undefined index:")!==false 100. || stripos($e->getMessage(),"Undefined offset:")!==false 101. || stripos($e->getMessage(),"Undefined variable:")!==false 102. ){ 103. //这是由Mongo日志记录抛出的异常 , 不能再把异常推进队列中, 否则会造成死循环 104. //这里用原生report方法 , 防止死循环 105. //类不存在的也不记录mongo日志 106. //变量未定义 , 也不记录mongo日志 107.                 parent::report($e); 108. return; 109. } 110. try{ 112. //取出异常的部分堆栈参数,方便排查问题 113.                 $args = $e->getTrace(); 114.                 $error_args = array_slice($args,0,5); 115. foreach($error_args as $k => $error){ 116. if(!isset($error['file'])){ 117.                         unset($error_args[$k]); 118. }elseif(isset($error['file'])&&(stripos($error['file'],'thinkphp')|| stripos($error['file'],'index.php'))){ 119.                         unset($error_args[$k]); 120. } 121. } 122. //异常信息丢到队列处理 123. QueueHelper::pushQueue("app\job\LogErrorMsg","log_error_msg",[ 124. 'msg_type'=>'exception', 125. 'system'=> env('system_name'), 126. 'error_num'=> $this->error_num, 127. 'error_handle'=>[ 128. 'file'=> $e->getFile(), 129. 'line'=> $e->getLine(), 130. 'msg'=> $e->getMessage(), 131. 'trace'=> $e->getTraceAsString(), 132. 'trace_args'=> $error_args, 133. ], 135. ]); 136. return; 137. }catch(\ErrorException $error){ 139. //入队异常 , 用原生report方法 , 防止死循环 140.                 parent::report($e); 141. return; 142. }catch(\Exception $error){ 144. //入队异常 , 用原生report方法 , 防止死循环 145.                 parent::report($e); 146. return; 147. } 148. // 使用内置的方式记录异常日志 149.             parent::report($e); 150. return; 151. } 152. } 153. } `