当你的接口报错时,你是不是看到的是如下的提示:
一般前端都是解析json格式的数据,上面的报错形式,导致前端无法正常解析,从而导致用户不知道发生了啥。
因为此时页面既没有操作成功的标志,也没有操作失败的提示。
之前我是在每个controller方法里加的try...catch...:
public function getLibWordEnOption()
{
try{
$service = new LibWordEnService();
$list = $service->getListNoPage($this->requestData);
return ResponseUtil::success($list);
}catch(\Exception $e){
CommonUtil::addErrorLog(__CLASS__, __FUNCTION__, CommonUtil::getExceptionMessage($e));
return ResponseUtil::failure("获取单词列表失败");
}
}
但这种方式有2个缺点:
加中间件。
这里细节就不跟大家展开了。
加中间件的方法行不通在于:
中间件是在方法执行前执行的,所以还没到发现异常这一步,自然也就无法捕获异常。
我测试的中间件代码放到文章末尾了,如果你不信,可以自己尝试看看。
一开始安装好thinkphp8框架,里面自带一个ExceptionHandle.php文件,就是用来统一处理异常的。
里面render方法已经告诉我们在哪里写下自己的处理逻辑:
我最终添加的代码如下,仅供参考:
public function render($request, Throwable $e): Response
{
// 添加自定义异常处理机制
$uri = $_SERVER['REQUEST_URI'];
$functionName = RequestUtil::getUriLastPart($uri);
$controllerName = RequestUtil::getUriMiddlePart($uri);
if($e instanceof HttpException){
return ResponseUtil::failure("请求失败");
}else if($e instanceof PDOException){
CommonUtil::addErrorLog($controllerName, $functionName, CommonUtil::getExceptionMessage($e));
return ResponseUtil::failure("数据库操作失败");
}else{
CommonUtil::addErrorLog($controllerName, $functionName, CommonUtil::getExceptionMessage($e));
return ResponseUtil::failure("程序错误");
}
// 其他错误交给系统处理
return parent::render($request, $e);
}
这样上面尝试方案里的2个问题就都被解决了。
本文为翟码农个人博客下技术主题里的php分类下的原创文章,跟大家分享如何在thinkphp8框架下统一处理异常,转载还请注明出处:http://www.zhai14.com/blog/how-to-change-api-response-into-json-format-when-meeting-error-in-thinkphp8.html
上面提到,如果controller方法里的try代码块出现语法错误,接口报错仍然是“页面错误!请稍后再试~”。
那为什么不能catch到呢?我们现在就来看看情况。
将上面示例的controller方法调整如下:
public function getLibWordEnOption()
{
echo "rrr";
try{
$service = new LibWordEnService();
$list = $service->getListNoPage($this->requestData)
return ResponseUtil::success($list);
}catch(\Exception $e){
CommonUtil::addErrorLog(__CLASS__, __FUNCTION__, CommonUtil::getExceptionMessage($e));
return ResponseUtil::failure("获取单词列表失败");
}
}
结果返回值如下:
{
"code": 0,
"message": "程序错误"
}
由此可见,走的是render方法里的else逻辑,我们再在else逻辑里把$e这个异常对象打印出来看看:
else{
print_r($e);
CommonUtil::addErrorLog($controllerName, $functionName, CommonUtil::getExceptionMessage($e));
return ResponseUtil::failure("程序错误");
}
结果显示如下:
异常对象是ErrorException,而不是Exception,所以catch不到。
不信的话,你就在render里再加个对ErrorException的判断来验证看看。
好了,已经回答了一开始的问题:接口报错,为何仍然是“页面错误!请稍后再试~”?
那为何我还另外加一行echo语句呢?
你有没有注意到,上面的测试结果,并没有输出“rrr”,这是为什么呢?
要想回答这个问题,那咱们就得了解php语言的执行原理了。关于这个,就后面再跟大家分享了。
namespace app\api\middleware;
use app\util\RequestUtil;
use app\util\ResponseUtil;
use think\exception\ErrorException;
class RecordException {
/**
* Desc: 如果有异常,将异常日志记录到mysql表里
* @param $request
* @param \Closure $next
* @return mixed
* Datetime: 2025/6/27 9:49 by coderzhai
*/
public function handle($request, \Closure $next) {
$controllerName = "";
$functionName = "";
try{
$uri = $_SERVER['REQUEST_URI'];
$functionName = RequestUtil::getUriLastPart($uri);
$controllerName = RequestUtil::getUriMiddlePart($uri);
echo $controllerName."-".$functionName;
$response = $next($request);
}catch(ErrorException $e){
return ResponseUtil::failure("请求中间件失败");
}
return $response;
}
}
路由文件里记得也要指定中间件,不然上面代码不会执行的:
})->allowCrossDomain()->middleware([RecordException::class]);