每次有运营或者产品同事跑过来跟我说“这个富文本又出问题了”,十有八九都是跟“标签”有关。做后端和前端的同学应该都有体会:项目刚接富文本编辑器的那几个月,基本是在跟 HTML 标签 斗智斗勇——存进去的内容莫名其妙带了一堆样式,导出 PDF 时排版稀烂,粘贴过来的内容带上一堆奇怪节点,更别提图片加载失败、链接点击跳转异常这些问题。
这里说的“标签”,不是浏览器里那个 tabs 标签页,也不是微信小程序的 <标签页组件>,而是富文本编辑器存储和渲染时的 HTML 标签体系。富文本编辑器本身做的事情很简单:把用户输入的富文本内容转成 HTML,或者说转成一组结构化的标签。可是一旦这套标签进入后端、再被不同端(Web 端、App、小程序、甚至邮件)渲染,问题就开始排队出现了。
这篇文章我打算把“富文本编辑器里的标签”这件事按我这些年实际踩坑的顺序拆开讲:从编辑器到底输出什么标签、为什么不能直接信任这些标签,到怎么清洗、怎么二次加工、怎么在前端安全渲染,再到图片、链接、PDF 下载这些高频疑难场景的应对。适合正在做 CMS 后台、BBS、工单系统、笔记应用,或者任何打算在项目里接入富文本编辑器的人,尤其是刚接手相关内容、正在排查各种诡异 bug 的同学。
1. 先弄清楚编辑器输出的“标签”到底是什么来路
1.1 同样是编辑框,各家生成的 HTML 完全不一样
不要以为富文本编辑器就是把文字变“富”而已。现在的编辑器底层大概分两类:一类基于 contenteditable,另一类是基于视图模型 + 自定义渲染。
基于 contenteditable 的老牌编辑器,用户输入什么浏览器行为就产生什么 DOM,比较接近你在网页上直接看到的内容。这类编辑器生成的标签风格比较“原始”,比如加粗可能直接用 <b>,也可能用 <strong>,颜色可能用 <font color="">,也可能是一堆内联 style="color: rgb(...)"。而后来出现的 Quill、TipTap、Slate 这些模型驱动的编辑器,会把内容转成自己的 Delta 或 JSON 结构,渲染时再定制生成标签。
同样是“粘贴一段来自网页的文字”,在老的编辑器里可能直接带进来 <div>、<span>、<a>,还有一堆内联样式;在某些编辑器里会被规范成 <p> 和 <strong> 这种干净结构。这不只是观感问题,后端拿到这些标签后是否安全、是否好渲染、是否能通过小程序端的富文本组件解析,都受影响。
我在对接后台系统时遇到过一个很常见的情况:编辑在后台用老编辑器写了一篇文章,里面用了 <table> 来实现排版,保存没问题,但用户端是 App 内嵌的 WebView,或者某些富文本原生组件,表格解析差,直接变成一堆乱码。这种现象背后是标签模型的差异,靠“换个前端组件”补不回来,必须从标签源头处理。
1.2 一个高频误区:标签只是“展示格式”吗
很多产品经理会觉得,用户加粗、变红、插个图,最终存的就是“带格式的文字”。但富文本存下来的标签其实是“可执行内容”。尤其当你用页面渲染富文本内容时,如果直接 v-html 或 dangerouslySetInnerHTML,这些标签不只是排版,它们还携带脚本、事件、资源加载。
例如用户粘贴来源不明的文本时,有可能带进带事件属性的标签,或者用 <iframe> 引用外部页面,又或者用 <meta>、<link> 这类标签去试图影响页面。在 Web 前端做“富文本展示”时,这种标签一旦被浏览器执行,轻则样式错乱,重则出现弹窗、跳转、页面被篡改等问题。这不是危言耸听,后台审核系统里最常被钻的空子就是“富文本内容里的标签没清洗”。
这里有个观念需要先纠正:富文本编辑器的标签输出,不是“存储格式”的终点,而是“安全过滤”的起点。编辑器负责给用户创作体验,后端负责把标签审一遍,前端渲染时再按业务规则加工一遍。任何时候都不建议直接把编辑器生成的 HTML 当成“安全可信数据”存库,更不建议把库里原样吐出的 HTML 直接渲染给终端用户。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 标签清洗怎么做:黑名单思路一定会漏
2.1 为什么只过滤 script 不靠谱
很多业务系统一开始处理用户提交的富文本,采用的是“黑名单”思维:把 <script>、<iframe>、onclick 这类危险标签和属性删掉,剩下的放行。听起来合理,但它有非常现实的问题:HTML 语言的组合方式太多,标签的属性组合、嵌套方式、编码方式都可以绕开简单过滤。
比如你以为删掉了 <script>,但用户粘贴的内容里可能有 <img src=x onerror=...>,这类标签在图片加载失败时会触发事件逻辑;你以为过滤了 javascript: 开头的内容,但超链接的 href 可能写成大小写混合或编码形式,照样被浏览器解析执行。黑名单维护成本很高,你今天堵住一个写法,明天可能冒出新的组合。
核心思路应当换成白名单:只放行你明确允许渲染的标签和属性,其他全部剥离。这样就算哪天新增了一个危险的标签写法,只要它不在白名单里,一样会被干掉。
2.2 一套实用的白名单清洗配置
目前业界比较标准的做法是使用 DOMPurify,它本身就是一个基于白名单的 HTML 标签清洗库。你不用自己手写正则去匹配标签(正则解析 HTML 本身就是坑)。配置时可以按项目需要,声明哪些标签和属性需要放行。
javascri复制
