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

Laravel异常中渲染HTML标签问题:换行及<br>标签无效

在Laravel异常中渲染美观的列表错误信息

嘿,我之前也踩过这个坑!Laravel默认处理异常时会自动转义所有输出的文本,所以你直接写的<br>会被转成&lt;br&gt;,\n在HTML里也只会被当成空格,自然不会生效。要实现带格式的错误列表,得换个思路,下面是几种靠谱的解决方法:

方法1:自定义异常类(最推荐)

创建一个专门的异常类来处理发票创建失败的场景,这样能更灵活地控制错误信息的渲染:

首先,新建异常文件app/Exceptions/InvoiceCreationFailedException.php:

namespace App\Exceptions;

use Exception;

class InvoiceCreationFailedException extends Exception
{
    protected $invalidProducts;

    // 构造函数接收无效产品数组
    public function __construct(array $invalidProducts)
    {
        $this->invalidProducts = $invalidProducts;
        parent::__construct('Could not create invoice.');
    }

    // 自定义渲染逻辑
    public function render($request)
    {
        // 构建安全的HTML列表(用e()转义内容防止XSS)
        $errorHtml = $this->getMessage() . '<ul class="mt-2">';
        foreach ($this->invalidProducts as $product) {
            // 这里根据你的产品结构调整,比如显示名称和错误原因
            $errorHtml .= '<li>' . e($product['name'] . ':' . $product['error']) . '</li>';
        }
        $errorHtml .= '</ul>';

        // 区分API请求和页面请求
        if ($request->expectsJson()) {
            return response()->json([
                'message' => $this->getMessage(),
                'invalid_products' => $this->invalidProducts
            ], 422);
        }

        // 返回自定义错误视图
        return view('errors.invoice-failed', ['errorHtml' => $errorHtml]);
    }
}

然后在你的业务代码里抛出这个异常:

if (count($notValidatedProducts) !== 0) {
    throw new \App\Exceptions\InvoiceCreationFailedException($notValidatedProducts);
}

最后创建对应的错误视图resources/views/errors/invoice-failed.blade.php:

<div class="alert alert-danger">
    {!! $errorHtml !!}
</div>

这里用{!! !!}而不是{{ }},因为我们已经提前用e()转义了内容,不会有XSS风险。

方法2:修改全局异常处理器

如果你不想创建自定义异常,也可以在全局异常处理器里做判断处理,打开app/Exceptions/Handler.php修改render方法:

public function render($request, Throwable $e)
{
    // 判断是否是发票创建失败的异常
    if ($e instanceof \Exception && str_starts_with($e->getMessage(), 'Could not create invoice')) {
        // 这里需要确保能拿到$notValidatedProducts,建议把它存在异常的自定义属性里
        // 或者你可以在抛出异常时把产品信息序列化到消息里,再在这里解析
        $invalidProducts = ...; // 替换成你的无效产品数组

        $errorHtml = $e->getMessage() . '<ul>';
        foreach ($invalidProducts as $product) {
            $errorHtml .= '<li>' . e($product) . '</li>';
        }
        $errorHtml .= '</ul>';

        if ($request->expectsJson()) {
            return response()->json(['error' => $errorHtml], 422);
        }

        return response()->view('errors.custom', ['error' => $errorHtml]);
    }

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

方法3:API场景返回结构化数据

如果是给API用的,直接返回结构化的JSON数据会更友好,前端可以自己渲染列表:

if (count($notValidatedProducts) !== 0) {
    throw new \Exception(json_encode([
        'message' => 'Could not create invoice.',
        'invalid_products' => $notValidatedProducts
    ]));
}

然后在全局异常处理器里解析这个JSON并返回:

public function render($request, Throwable $e)
{
    $message = $e->getMessage();
    // 判断是否是JSON格式的异常消息
    if (json_validate($message)) {
        $errorData = json_decode($message, true);
        return response()->json($errorData, 422);
    }

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

关键提醒

不管用哪种方法,一定要用e()函数转义用户输入的内容(比如产品名称、错误原因),防止XSS攻击。Laravel的{{ }}默认会转义,但如果用{!! !!}输出HTML,必须提前做好转义处理。

内容的提问来源于stack exchange,提问作者Anna Jeanine

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:03:41