上一篇:常用网址大全(2025-06-27 19:48:32)
文章大纲

在thinkphp8框架里,当接口报错时,怎么把返回值统一改成json格式?

2025-06-27 21:16:03

问题描述

当你的接口报错时,你是不是看到的是如下的提示:

一般前端都是解析json格式的数据,上面的报错形式,导致前端无法正常解析,从而导致用户不知道发生了啥。

因为此时页面既没有操作成功的标志,也没有操作失败的提示。


尝试方案1

之前我是在每个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个缺点:

  1. 当try代码块里出现语法错误时,接口仍然显示的是“页面错误!请稍后再试~”,不是规范的json格式。
  2. 每个controller里的方法都要加,不仅增加工作量,而且万一以后错误日志方法需要新增参数,修改牵连的范围也太广。


尝试方案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("获取单词列表失败");
}
}
  1. 加了一行echo
  2. 去掉了getListNoPage这一行末尾的分号(引入语法错误)

结果返回值如下:

txt
{
    "code": 0,
    "message": "程序错误"
}


由此可见,走的是render方法里的else逻辑,我们再在else逻辑里把$e这个异常对象打印出来看看:

php
else{
    print_r($e);
    CommonUtil::addErrorLog($controllerName, $functionName,  CommonUtil::getExceptionMessage($e));
    return ResponseUtil::failure("程序错误");
}

结果显示如下:


异常对象是ErrorException,而不是Exception,所以catch不到。

不信的话,你就在render里再加个对ErrorException的判断来验证看看。


好了,已经回答了一开始的问题:接口报错,为何仍然是“页面错误!请稍后再试~”?

那为何我还另外加一行echo语句呢?

你有没有注意到,上面的测试结果,并没有输出“rrr”,这是为什么呢?

要想回答这个问题,那咱们就得了解php语言的执行原理了。关于这个,就后面再跟大家分享了。


中间件测试代码

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;
    }
}

路由文件里记得也要指定中间件,不然上面代码不会执行的:

php
})->allowCrossDomain()->middleware([RecordException::class]);



上一篇:常用网址大全(2025-06-27 19:48:32)
我要评论
评论列表