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