使用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. }
`