ThinkPHP6项目基操(13.实战部分 项目中的自定义异常处理总结 错误页面&API错误)

前言

  一般项目中路由分为返回模板引擎页面和返回api接口json数据,两种方式异常需要返回不同的内容,如果是模板引擎页面遇到异常需要返回错误页面,如果是api接口遇到异常需要返回json数据。
  开发模式和上线模式应该返回不同的内容,开发模式应该尽可能返回具体的错误信息,上线模式则不能返回具体的错误信息,一般显示“服务器错误,请稍后重试”类似友好的提示,而不是显示一堆报错代码(既不友好又不安全)。
  如果有更好的方法,欢迎提出意见。

一、异常分类

1. 控制器找不到

在访问路由时,若控制器不对,需要使用空控制器拦截报错。

2. 方法找不到

方法找不到可以修改app目录下的BaseController控制器重写__call方法。

3. 请求资源不存在

自定义拦截报错信息,可以使用Provider自定义错误处理类,重写render方法,根据不同的错误返回不同的数据。

4. 系统內部异常、HTTP异常等

同第3点。

二、异常处理

1. 前置处理

(1) .env文件定义APP_DEBUG区分开发模式和线上模式,true表示开发模式,false表示线上模式:

APP_DEBUG = true

(2) 在app/common.php 文件定义api返回的数据格式:

function show($status, $message = 'error', $data = [], $httpStatus = 200){
    $result = [
        "status" => $status,
        "message" => $message,
        "result" => $data
    ];
    return json($result, $httpStatus);
}

(3) 在当前应用下新建一个provider.php,并指定自定义异常处理类:

<?php

// 容器Provider定义文件
return [
    'think\exception\Handle' => 'app\\admin\\exception\\Http',
];

(4) 定义状态码配置,可以在config文件夹下新建status.php添加相应的状态码配置:

<?php

return [
    "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

namespace 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 方法:

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

namespace 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)显示:

<p class="error-message">{$e ?? ''}</p>

三、异常检测

异常检测分浏览器页面访问异常api接口返回异常,还需要检查开发模式线上模式

  1. 控制器不存在
  2. 方法不存在
  3. 主动抛出异常
  4. 系统抛出异常

Tips: api接口可以使用Postman工具模拟,添加Headers
Content-Typeapplication/x-www-form-urlencoded
X-Requested-Withxmlhttprequest

(博主比较懒就不贴截图了,但是都测试过,同志们自己试一下,算了还是贴一张吧)
在这里插入图片描述


⭐️重磅推荐:免费商用电商系统

😏想白嫖整个电商系统用来商用?
🤑想有自己的商城实现财富自由?
🤓想学习最佳实践提升自己技术?

快来进入🚀 传送门 🚀,开源免费、完整示例带你快速入门,轻松二开,走上人生巅峰!👨‍🎓
在这里插入图片描述

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
thinkphp6,可以通过以下方式自定义抛出异常: 1. 创建自定义异常类 首先,我们需要创建一个自定义的异常类,继承自think\Exception类,例如: ```php namespace app\exception; use think\Exception; class MyException extends Exception { protected $message = '自定义异常信息'; protected $code = 10001; } ``` 在上面的例子,我们创建了一个名为MyException的自定义异常类,设置了异常信息和异常代码。 2. 抛出自定义异常 在需要抛出异常的地方,可以通过以下方式抛出自定义异常: ```php throw new MyException(); ``` 或者: ```php throw new MyException('自定义异常信息', 10001); ``` 在上面的例子,我们使用了自定义异常类MyException,并传入了异常信息和异常代码。 3. 异常处理 最后,我们需要在异常处理的地方捕获并处理自定义异常,例如: ```php namespace app\exception; use think\exception\Handle; class ExceptionHandle extends Handle { public function render(\Exception $e) { if ($e instanceof MyException) { // 处理自定义异常 return json(['code' => $e->getCode(), 'msg' => $e->getMessage()]); } // 其他异常交给系统处理 return parent::render($e); } } ``` 在上面的例子,我们创建了一个名为ExceptionHandle的异常处理类,继承自think\exception\Handle类,重写了render方法,在该方法捕获并处理自定义异常MyException。 当系统抛出自定义异常时,会调用ExceptionHandle的render方法进行处理,返回一个相应的响应结果。如果抛出的异常不是自定义异常,则交给系统默认的异常处理方式处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

优小U

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值