响应拦截器不负责HTML安全过滤,真正过滤必须在渲染前用DOMPurify等专业库完成;因拦截器处理JSON响应体,HTML常藏于字段中,全量净化会破坏结构且违反关注点分离;正确做法是在组件层按需净化并缓存结果,前端二次净化是纵深防御必要环节。

响应拦截器本身不负责 HTML 安全过滤,它只做数据流转和格式统一。真正过滤 HTML 的动作必须发生在渲染前、且必须使用专业净化库——DOMPurify 是当前最可靠的选择。
为什么不能在响应拦截器里直接 sanitize?
因为拦截器处理的是原始响应体(通常是 JSON),而 HTML 片段往往藏在某个字段里(比如 data.content 或 data.html),不是整个响应体。盲目对整个 response.data 调用 DOMPurify 会破坏结构化数据,也可能漏掉嵌套字段中的危险内容。
更关键的是:拦截器属于请求层,而 HTML 渲染属于视图层。把 DOM 操作逻辑塞进拦截器,违反关注点分离原则,也容易导致 SSR 不兼容、服务端预渲染失败等问题。
正确做法:在组件或业务逻辑层按需净化
拿到后端返回的 HTML 字符串后,在真正要渲染前调用 DOMPurify.sanitize()。例如:
立即学习“前端免费学习笔记(深入)”;
- 在 setup 中用
computed缓存净化结果,避免重复执行 - 若 HTML 来自富文本编辑器(如 TipTap),优先消费其 JSON 结构,而非导出 HTML 后再渲染
- 若必须动态插入,配合
v-html使用时,确保传入的值已是 DOMPurify 处理后的干净字符串
示例代码:
import { computed } from 'vue'
import DOMPurify from 'dompurify'
<p>export default {
props: ['rawHtml'],
setup(props) {
const cleanHtml = computed(() =>
DOMPurify.sanitize(props.rawHtml, {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'ul', 'ol', 'li'],
ALLOWED_ATTR: ['class'],
SAFE_FOR_TEMPLATES: true // 防止 style 中的 CSS 表达式
})
)
return { cleanHtml }
}
}</p>后端已过滤,前端还要做吗?
要。服务端净化只能防住传输链路中的风险,但前端仍可能因以下原因引入 XSS:
- 前端拼接 data-* 属性后重新 innerHTML 插入
- 用户通过 devtools 修改 DOM,绕过后端校验
- CDN 缓存污染或中间人篡改响应
所以前端二次净化是纵深防御的必要一环,配置应与后端一致,且启用 SAFE_FOR_TEMPLATES: true。
别踩这些坑
常见错误包括:
- 用正则替换
on\w+=或删<script>—— 完全不可靠,大小写混淆、注释分隔、UTF-8 编码都能绕过 - 自己写白名单解析器 —— HTML 解析极其复杂,浏览器才是唯一可信解析器
- 在
setup()中每次调用DOMPurify.sanitize()而不做缓存 —— 性能损耗明显,尤其高频更新场景



















