SpringBoot + Vue3 解决HTML反转义导致JSON解析失败的方案

最近做前后端分离项目遇到一个很迷惑的 bug,在这里记录一下。

为了防止 XSS 和特殊字符存储问题,数据库里直接存了 HTML 转义后的实体,像"<这类。很多同事的做法是在 Java 业务代码里循环列表,拿到实体之后直接对字段做 HTML 反转义。

但这个写法有坑:接口返回状态码明明是 200,前端却一直报数据加载失败、JSON 解析错误。一旦把后端的反转义代码注释掉,接口马上恢复正常。

原因其实不难理解。 数据库里原始保存的字符串是"10"钢管,后端手动反转义之后,就变成了"10"钢管"。字符串里面出现了裸双引号。如果这个时候直接 set 进实体对象,等到 Jackson 序列化生成 JSON 的时候,引号会直接打乱 JSON 结构,最终生成非法的 JSON 文本,类似下面这样:

复制代码
{
  "spec": "10"钢管""
}

而没做解码的"只是普通文本字符,不会干扰 JSON 语法,所以可以正常解析。

千万不要写这种代码,生产环境踩坑概率极高

复制代码
// 错误写法!
for (Entity entity : list) {
    entity.setSpec(HtmlUtil.smartUnescapeHtml(entity.getSpec()));
}

提前修改实体字段,等于在序列化之前就把裸引号、特殊符号塞到对象里,最后输出的 JSON 报文直接损坏。

方案一:SpringBoot 后端处理,适合多端项目

思路很简单:不去改动实体里面原始的值,把 HTML 解码放到 Jackson 序列化阶段。序列化输出的时候再处理,Jackson 会自动帮我们转义 JSON 敏感字符,保证报文合法,Vue、小程序、APP 都能拿到已经解码好的文本。

先写 HTML 反转义工具类:

复制代码
import org.apache.commons.lang3.StringEscapeUtils;

public class HtmlUnEscapeUtil {
    /**
     * 智能HTML反转义
     * 兼容项目u0026特殊转义残留,还原标准HTML实体字符
     */
    public static String smartUnescapeHtml(String s) {
        if (s == null) return null;
        // 兼容项目特有 u0026 转义残留
        s = s.replace("u0026", "&");
        // 标准HTML实体反转义
        return StringEscapeUtils.unescapeHtml(s);
    }
}

自定义 Jackson 序列化器:

复制代码
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;

public class HtmlUnescapeSerializer extends JsonSerializer<String> {
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value == null) {
            gen.writeNull();
            return;
        }
        // 解码后由Jackson自动完成JSON特殊字符转义,保证报文合法
        gen.writeString(HtmlUnEscapeUtil.smartUnescapeHtml(value));
    }
}

DTO 上通过注解指定哪些字段需要自动解码,按需启用:

复制代码
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

public class GoodsDTO {
    // 规格字段自动HTML反转义
    @JsonSerialize(using = HtmlUnescapeSerializer.class)
    private String spec;

    // 描述字段自动HTML反转义
    @JsonSerialize(using = HtmlUnescapeSerializer.class)
    private String description;

    // getter、setter
}

这种方式好处很明显:实体原始数据不会被污染,JSON 报文始终合法;所有客户端拿到的都是解码完成的文本。缺点就是需要新增序列化器,DTO 需要加注解,少量改造后端代码。

方案二:Vue3 前端渲染解码,后端完全不用改

如果只需要后台页面展示,不想动后端代码,就可以选择在前端渲染的时候再解码。后端原样返回带 HTML 实体的原始字符串,在 Vue 渲染阶段处理,从根源避开后端 JSON 损坏的风险。

前端工具函数,逻辑和后端保持一致:

复制代码
// utils/html.js 全局工具方法
export function smartUnescapeHtml(s) {
  if (!s) return s;
  // 兼容后端u0026特殊转义字符
  let str = s.replace(/u0026/g, "&");
  const dom = document.createElement("div");
  dom.innerHTML = str;
  // 采用innerText解析,自动规避XSS风险,只输出纯文本
  return dom.innerText;
}

Vue3 + Element Plus 表格示例,直接在模板里调用:

复制代码
<template>
  <el-table :data="tableData" border>
    <el-table-column label="规格" prop="spec">
      <template #default="{ row }">
        {{ smartUnescapeHtml(row.spec) }}
      </template>
    </el-table-column>

    <el-table-column label="商品描述" prop="description">
      <template #default="{ row }">
        {{ smartUnescapeHtml(row.description) }}
      </template>
    </el-table-column>
  </el-table>
</template>

<script setup>
import { ref } from "vue";
import { smartUnescapeHtml } from "@/utils/html";
const tableData = ref([]);
</script>

如果文本太长需要截断,顺序一定要注意:先解码,再截取。如果反过来,HTML 实体被截断一半,就会出现乱码。

复制代码
// 超长文本格式化展示
function getShowText(val, len = 10) {
  // 优先解码,再做长度截取
  const str = smartUnescapeHtml(val);
  if (!str) return "";
  return str.length > len ? str.slice(0, len) + "..." : str;
}
  • 多端共用接口(Vue、小程序、APP),需要统一展示效果:选 SpringBoot 自定义序列化器。全局统一处理,前端不用关心解码逻辑。
  • 仅仅后台管理页面展示,其他端保留原始转义文本:直接 Vue 前端渲染解码,改造成本最低。

开发避坑小结

  1. 不要在循环实体的时候 set 解码后的字符串,这是 JSON 报错最常见的原因;
  2. HTTP 返回 200 不代表数据没问题,只是网络请求成功,JSON 语法错误照样解析失败;
  3. 后端解码要放在序列化阶段,业务层不要修改原始实体字段;
  4. 前端文本处理顺序:先解码,再做截取、格式化、渲染;
  5. 前端用 innerText 获取文本,不会执行脚本,不用担心 XSS。

常见疑问

Q:接口返回 HTTP 200,为什么前端还是解析失败?

A:200 只是网络层面请求成功。后端反转义生成的裸引号会破坏 JSON 语法,前端 JS 解析 JSON 直接抛出异常,页面表现就是加载失败。
Q:生产环境优先选哪套方案?

A:多端共用接口优先后端序列化方式;只有 Vue 后台页面使用,前端解码更省事。
Q:前端这种解码会不会有 XSS 风险?

A:这里用 innerText,只会读取纯文本,不会解析执行 html 脚本,生产环境安全可用。

相关推荐
H0311169852 小时前
QuestMobile之外的数据分析平台信息整理:月狐数据、友盟+、GrowingIO
人工智能
桃西西呀2 小时前
Agent说做完了,其实什么都没改:静默失败原因拆解
人工智能·llm·agent
骑士雄师2 小时前
鉴权遗留问题
人工智能
政企项目老覃2 小时前
大模型 Agent 自主任务编排:电商客服地址解析从 12% 失败率到 2.1% 的落地复盘
人工智能·程序人生·算法
DQQzero2 小时前
豆包工作来了:AI办公三国杀的牌桌重组
人工智能·ai·大模型·办公
u1301302 小时前
GitHub 热榜项目:日榜(2026-09-20)
人工智能·github
AKAMAI2 小时前
Akamai 云服务持续强化其基础架构(更新时间:2026年8月)
人工智能·云计算