企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
### 项目中的自定义异常处理总结 错误页面&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` (博主比较懒就不贴截图了,但是都测试过,同志们自己试一下,算了还是贴一张吧)