tp5 API 自定义全局异常处理(补充)

tp5 自带的错误页面是非常清晰的,而客户端的开发者需要一个简化的 json 信息,前面的上中下三篇已经具体介绍了如何返回 json 信息,但是作为客户端开发我们还是希望使用 tp5 自带的错误页面来定位错误,这样如何调和呢?我们可以通过一个开关来进行操作,开关开的时候返回具体的包含错误信息的 html 页面,如果开关是关闭的我们就返回 json。
我们先附上我们现在已经有的 ExceptionHandler 类:

code = $e->code;
            $this->msg = $e->msg;
            $this->errorCode = $e->errorCode;
        } else {
            $this->code = 500;
            $this->msg = "服务器内部错误";
            $this->errorCode = 999;
            $this->recordErrorlog($e);
        }

        $request = Request::instance();

        $result = [
            'msg' => $this->msg,
            'error_code' => $this->errorCode,
            'request_url' => $request->url()
        ];

        return json($result, $this->code);
    }

    private function recordErrorlog(Exception $e)
    {
        Log::init([
            'type' => 'File',
            'path' => LOG_PATH,
            'level' => ['error']
        ]);
        Log::record($e->getMessage(), 'error');
    }
}

现在我们来分析一下思路,我们通过自己写的 render 方法覆盖了父类的 render 方法,所以当我们需要重新调用父类 render 方法的时候,我们重新将 else 里面的代码用伪代码的形式补充一下:

if ($e instanceof BaseException) {
  // 自定义的异常
  $this->code = $e->code;
  $this->msg = $e->msg;
  $this->errorCode = $e->errorCode;
} else {
  if( 开关 ){
    return parent::render($e);
  } else {
    $this->code = 500;
    $this->msg = "服务器内部错误";
    $this->errorCode = 999;
    $this->recordErrorlog($e);
  }
}

即,当在开发模式下的时候,我们可以通过开关,返回 Handle 类的 render 方法的结果,这样我们就可以看到一个页面了,而生产模式的时候,可以关闭该模式,就会返回 json 了。
那么我们基本完成了,现在我们来确定一下用什么当我们的这个开关。
我们找到 config.php 文件,里面有个 app_debug 的常量,这个就非常适合我们的场景。
于是我们将以下代码放到 if 的判断中即可:

if( config('app_debug') )

config 是 tp5 的一个助手函数,我们可以通过它快速读取 config 中的信息,同时我们还有另外一种写法:
Config::get('app_debug')

我们还有一个目标,这里先以我们的参数校验层举例,当我们通过 goCheck 进行拦截时,需要这样写:

public function goCheck()
{
  $request = Request::instance();
  $params = $request->param();

  $result = $this->batch()->check($params);
  if (!$result) {
    $e = new ParameterException();
    $e.msg = $this->error; // 这行代码不如使用面向对象的思想来做
    throw $e;
  } else {
    return true;
  }
}

我们在 BaseException 中添加构造器:

public function __construct($params = [])
{
  if (!is_array($params)){
    return;  // 如果没有传入数组,那么就是使用默认的 code、msg 和 errorCode
   }
  if (array_key_exists('code',$params)){
    $this->code = $params['code'];
  }
  if (array_key_exists('msg',$params)){
    $this->msg = $params['msg'];
  }
  if (array_key_exists('errorCode',$params)){
    $this->errorCode = $params['errorCode'];
  }
}

然后将这 goCheck 中的这两行代码:

$e = new ParameterException();
$e.msg = $this->error; 

替换为:

$e = new ParameterException([
  'msg' => $this->error;
])

最后一个小问题是,例如我们故意输入错误的 url 时,会发现以下展示页面:

tp5 API 自定义全局异常处理(补充)_第1张图片
提示我们 render 方法中传参出现了错误

这是因为当 url 错误的时候抛出的是 HttpException 错误,而我们之前写的 think/Exception 并不是 HttpException 的父类,转换时出现了问题。
错误原因: public function render(Exception $e){
所以我们需要找到 think/Exception 与 HttpException 的共同的父类。
只要我们将 ExceptionHandler 中用到 think/Exception 的两个地方(一个 render 的参数,一个是 recordErrorlog 的参数)替换为基类 \Exception 即可:(\ 代表根目录下,与命名空间的知识相关)

public function render(\Exception $e){...
private function recordErrorlog(\Exception $e){...
tp5 API 自定义全局异常处理(补充)_第2张图片
期望的返回结果

你可能感兴趣的:(tp5 API 自定义全局异常处理(补充))