You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确抛出PHP自定义异常以返回数组格式响应?

问题:如何让CustomException抛出的message为合法JSON对象?

我现在有一段验证错误处理的代码:

$errors = $this->validator->validate($request);

if (\count($errors) > 0) {
    $errorBag = ErrorMessageHelper::generateErrorMessage($errors);

    throw new CustomException(json_encode($errorBag), Response::HTTP_INTERNAL_SERVER_ERROR);
}

这里的$errorBag是一个数组,抛出异常后,返回的响应格式是这样的:

"error":{"code":500,"message":"{\"postalCode\":\"This value should have exactly 7 characters.\"}"}

可以看到message是JSON编码后的字符串,而不是合法的JSON对象。我尝试过重写CustomException,但不仅没效果,还返回了空响应,求可行的解决思路。


解决思路与方案

兄弟,我之前也碰到过类似的问题,核心问题其实不是重写异常类本身,而是你的**全局异常处理器(或异常处理中间件)**在输出响应时的逻辑有问题。给你几个可行的方向:

1. 调整CustomException的设计,直接接收数组

别先把$errorBag转成JSON字符串再传给异常,直接把数组存到异常实例里,这样后续处理更灵活。修改CustomException的构造函数:

class CustomException extends \Exception
{
    protected array $errorData;

    public function __construct(array $errorData, int $code = 0, \Throwable $previous = null)
    {
        // 这里的消息可以设为通用提示,或者留空,反正后续不用它
        parent::__construct('Validation failed', $code, $previous);
        $this->errorData = $errorData;
    }

    // 提供获取错误数组的方法
    public function getErrorData(): array
    {
        return $this->errorData;
    }
}

然后抛出异常时直接传数组:

throw new CustomException($errorBag, Response::HTTP_INTERNAL_SERVER_ERROR);

2. 修复全局异常处理器的响应格式化逻辑

这才是关键!之前你重写异常类没用,大概率是因为全局异常处理的地方,还是把getMessage()的结果直接当成字符串塞到响应里了。以Laravel为例,找到App\Exceptions\Handler类,修改render方法:

public function render($request, Throwable $exception)
{
    // 针对CustomException做特殊处理
    if ($exception instanceof CustomException) {
        return response()->json([
            'error' => [
                'code' => $exception->getCode(),
                'message' => $exception->getErrorData() // 直接传数组,框架自动转成JSON对象
            ]
        ], $exception->getCode());
    }

    // 其他异常交给默认处理逻辑
    return parent::render($request, $exception);
}

这样返回的响应里,message就是合法的JSON对象了,不会出现嵌套转义的问题。

3. 退而求其次:不修改异常类的方案

要是你暂时不想动CustomException的结构,那就在异常处理器里把message的JSON字符串解码成数组再输出:

public function render($request, Throwable $exception)
{
    if ($exception instanceof CustomException) {
        // 解码JSON字符串
        $errorMessage = json_decode($exception->getMessage(), true);
        // 加个判断,避免解码失败导致的错误
        if (json_last_error() !== JSON_ERROR_NONE) {
            $errorMessage = $exception->getMessage();
        }

        return response()->json([
            'error' => [
                'code' => $exception->getCode(),
                'message' => $errorMessage
            ]
        ], $exception->getCode());
    }

    return parent::render($request, $exception);
}

总结

核心逻辑就是:让响应生成时直接接收数组类型的错误数据,框架的json()方法会自动把数组转换成合法的JSON对象;如果先把数组转成JSON字符串再塞进去,只会导致响应里的message变成转义后的字符串,这就是你之前遇到的问题。

内容的提问来源于stack exchange,提问作者Suraj Gusain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:13:51