### 項目中的自定義異常處理總結 錯誤頁面&API錯誤
* 前言
* 一、異常分類
* * 1\. 控制器找不到
* 2\. 方法找不到
* 3\. 請求資源不存在
* 4\. 系統內部異常、HTTP異常等
* 二、異常處理
* * 1\. 前置處理
* 2\. 異常處理詳細代碼
* * (1) 控制器找不到
* (2) 方法找不到
* (3) 請求資源不存在及系統錯誤異常
* 三、異常檢測
# 前言
??一般項目中路由分為返回`模板引擎頁面`和返回`api接口json數據`,兩種方式異常需要返回不同的內容,如果是模板引擎頁面遇到異常需要返回錯誤頁面,如果是api接口遇到異常需要返回json數據。
??開發模式和上線模式應該返回不同的內容,開發模式應該盡可能返回具體的錯誤信息,上線模式則不能返回具體的錯誤信息,一般顯示“服務器錯誤,請稍后重試”類似友好的提示,而不是顯示一堆報錯代碼(既不友好又不安全)。
??如果有更好的方法,歡迎提出意見。
# 一、異常分類
## 1\. 控制器找不到
在訪問路由時,若控制器不對,需要使用`空控制器`攔截報錯。
## 2\. 方法找不到
方法找不到可以修改app目錄下的BaseController控制器重寫\_\_call方法。
## 3\. 請求資源不存在
自定義攔截報錯信息,可以使用Provider自定義錯誤處理類,重寫render方法,根據不同的錯誤返回不同的數據。
## 4\. 系統內部異常、HTTP異常等
同第3點。
# 二、異常處理
## 1\. 前置處理
> (1)`.env`文件定義`APP_DEBUG`區分開發模式和線上模式,true表示開發模式,false表示線上模式:
~~~php
APP_DEBUG = true
~~~
> (2) 在`app/common.php`文件定義`api`返回的數據格式:
~~~php
function show($status, $message = 'error', $data = [], $httpStatus = 200){$result = ["status" => $status,"message" => $message,"result" => $data];return json($result, $httpStatus);
}
~~~
> (3) 在當前應用下新建一個provider.php,并指定自定義異常處理類:
~~~php
<?php// 容器Provider定義文件
return ['think\exception\Handle' => 'app\\admin\\exception\\Http',
];
~~~
> (4) 定義狀態碼配置,可以在`config`文件夾下新建`status.php`添加相應的狀態碼配置:
~~~php
<?phpreturn ["success" => 1,"error" => 0,"http_status" => ["not_found" => 404,"validate_error" => 422,"internal_error" => 500]
];
~~~
> (5) 準備錯誤頁面(404,500等)
## 2\. 異常處理詳細代碼
### (1) 控制器找不到
在`app/controller`目錄新建`Error`類(`文件名固定為Error`):
> `這里需要注意的是,多應用的控制器應該定義在應用文件夾里,這里定義在app目錄是為了作用于app下全部應用。`
~~~php
<?phpnamespace app\controller;class Error
{public function __call($name, $arguments){if(request()->isAjax()){return show(config("status.error"), env('app_debug') ? "控制器{$name}找不到" : '當前請求資源不存在,請稍后再試', [], config("status.http_status.not_found"));}else{return view(root_path() . 'public/error/admin/404.html', ['e' => env('app_debug') ? "控制器{$name}找不到" : '當前請求資源不存在,請稍后再試'], config("status.http_status.not_found"));}}
}
~~~
### (2) 方法找不到
在`app/BaseController.php`控制器添加`__call`方法:
~~~php
public function __call($name, $arguments){if(request()->isAjax()){return show(config("status.error"), env('app_debug') ? "找不到{$name}方法" : '當前請求資源不存在,請稍后再試', [], config("status.http_status.not_found"));}else{return view(root_path() . 'public/error/admin/404.html', ['e' => env('app_debug') ? "{$name}方法找不到" : '當前請求資源不存在,請稍后再試'], config("status.http_status.not_found"));}}
~~~
### (3) 請求資源不存在及系統錯誤異常
`app\\admin\\exception\\Http`:
~~~php
<?phpnamespace app\admin\exception;
use ErrorException;
use Exception;
use InvalidArgumentException;
use ParseError;
use PDOException;
use think\exception\ClassNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\RouteNotFoundException;
use think\Response;
use Throwable;
use TypeError;class Http extends Handle
{/*** Render an exception into an HTTP response.** @access public* @param \think\Request $request* @param Throwable $e* @return Response*/public function render($request, Throwable $e): Response{$returnCode = config("status.error");$returnMessage = "系統異常,請稍后再試";$returnData = [];$httpStatus = 500;if($e instanceof BusinessException){ // 自定義添加的業務異常$returnMessage = $e->getMessage();$httpStatus = config("status.http_status.business_error");}else if($e instanceof ValidateException){$returnMessage = $e->getError();$httpStatus = config("status.http_status.validate_error");}else if (($e instanceof ClassNotFoundException || $e instanceof RouteNotFoundException) || ($e instanceof HttpException && $e->getStatusCode() == 404)) {$returnMessage = env('app_debug') ? $e->getMessage() : '當前請求資源不存在,請稍后再試';$httpStatus = config("status.http_status.not_found");}else if ($e instanceof Exception || $e instanceof PDOException || $e instanceof InvalidArgumentException || $e instanceof ErrorException || $e instanceof ParseError || $e instanceof TypeError || ($e instanceof HttpException && $e->getStatusCode() == 500)) {$returnMessage = env('app_debug') ? $e->getMessage() : '系統異常,請稍后再試';$httpStatus = config("status.http_status.internal_error");}if(request()->isAjax()){return show($returnCode, $returnMessage, $returnData, $httpStatus);}else{if($httpStatus == config("status.http_status.not_found")){$errorUrl = 'public/error/admin/404.html';}else{$errorUrl = 'public/error/admin/error.html';}return view(root_path() . $errorUrl, ['e'=>$returnMessage], $httpStatus);}}
}
~~~
以上代碼中返回的錯誤信息`e`,需要在錯誤頁面(404,error)顯示:
~~~html
<p class="error-message">{$e ?? ''}</p>
~~~
# 三、異常檢測
異常檢測分瀏覽器`頁面訪問異常`和`api接口返回異常`,還需要檢查`開發模式`和`線上模式`。
1. 控制器不存在
2. 方法不存在
3. 主動拋出異常
4. 系統拋出異常
> Tips:`api`接口可以使用`Postman`工具模擬,添加`Headers`:
> `Content-Type`為`application/x-www-form-urlencoded`
> `X-Requested-With`為`xmlhttprequest`
(博主比較懶就不貼截圖了,但是都測試過,同志們自己試一下,算了還是貼一張吧)
- 空白目錄
- 使用thinkphp6搭建后端api接口流程
- tp6 uniapp vue 前后端跨域解決方案
- 操作記錄
- api00
- 你看看有沒有用
- 6666
- Docker安裝LNMP環境的詳細過程(可部署TP項目)
- LNMP部署thinkphp
- 玩客云Armbian 安裝LNMP環境 Docker
- ThinkPHP6項目基操(16.實戰部分 redis+token登錄)
- ThinkPHP6項目基操(11.實戰部分 部署后臺靜態頁面模板及后臺登錄頁面)
- ThinkPHP6項目基操(13.實戰部分 項目中的自定義異常處理總結 錯誤頁面API錯誤)
- ThinkPHP6項目基操(14.實戰部分 中間件處理登錄流程)
- ThinkPHP6項目基操(12.實戰部分 驗證碼)
- ThinkPHP6項目基操(18.實戰部分 表單令牌Token 防CSRF)
- ThinkPHP6項目基操(19.實戰部分 Mysql模型事務操作)
- ThinkPHP6項目基操(20.實戰部分 數據庫操作返回值總結)
- 瀏覽器端判斷當前設備的運行環境
- api
- api異常捕捉
- 寫一個中間件
- 統一的參數返回形式
- ThinkPHP6調用模型的方法
- thinkphp6控制器、驗證器、模型、service,各層寫的內容