tp5 自带的错误页面是非常清晰的,而客户端的开发者需要一个简化的 json 信息,前面的上中下三篇已经具体介绍了如何返回 json 信息,但是作为客户端开发我们还是希望使用 tp5 自带的错误页面来定位错误,这样如何调和呢?我们可以通过一个开关来进行操作,开关开的时候返回具体的包含错误信息的 html 页面,如果开关是关闭的我们就返回 json。
我们先附上我们现在已经有的 ExceptionHandler 类:
<?php
namespace app\lib\exception;
use tests\thinkphp\library\think\logTest;
use think\Exception;
use think\exception\Handle;
use think\Request;
use think\Log;
class ExceptionHandler extends Handle
{
private $code;
private $msg;
private $errorCode;
// 还需要返回客户端当前请求的url路径
public function render(Exception $e)
{
if ($e instanceof BaseException) {
// 自定义的异常
$this->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 时,会发现以下展示页面:
这是因为当 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){...
期望的返回结果
网友评论