1. 基本概念与场景需求
在前端开发中,用户可能会输入包含 HTML 的文本内容,为了保证页面安全性,需要对这些内容进行转义,同时为了提升呈现效果,通常又希望能<有选择地保留指定标签而非全部转义。
这类需求正好对 在 JavaScript 中实现 HTML 标签转义时如何有选择地保留指定标签提出了挑战:要实现对标签的白名单控制,同时确保潜在的 XSS 风险被抑制。
1.1 需求背景与白名单概念
一个常见的白名单示例是:允许保留的标签包括 a、strong、em、b、i、p、ul、li、br 等,其他标签都需要被转义或移除。
另外,属性的清洗也很重要,例如对 a 标签的 href 属性进行约束,避免携带 javascript: 等危险协议。
2. 实现方式与核心算法
实现这类需求的思路大致分为两类:一种是基于浏览器内置的 DOM 遍历清洗,另一种是借助成熟库来快速落地,这两者在灵活性和安全性上各有取舍。
在选择实现方式时,需要权衡可控性、性能与安全性等因素,确保不会在提升体验的同时引入新的风险。
2.1 基于 DOM 的实现思路
核心步骤是将输入字符串解析为 DOM,递归遍历每个节点,保留白名单中的元素,对非白名单节点进行提取子节点或完全移除的处理。

此外,对保留标签的属性进行清洗,确保 href、src 等属性不携带危险的值,例如避免 javascript:。
function sanitizeHtmlWithWhitelist(html, allowedTags, allowedAttrs) {const parser = new DOMParser();const doc = parser.parseFromString(html, 'text/html');const body = doc.body;function walk(node) {if (node.nodeType === 3) return; // textif (node.nodeType !== 1) return;const tag = node.tagName.toLowerCase();if (!allowedTags.includes(tag)) {// unwrap non-白名单节点const parent = node.parentNode;while (node.firstChild) parent.insertBefore(node.firstChild, node);parent.removeChild(node);return;}// 清洗属性const attrs = Array.from(node.attributes);for (const attr of attrs) {let keep = false;if (allowedAttrs && allowedAttrs[tag] && allowedAttrs[tag].includes(attr.name.toLowerCase())) {keep = true;}if (!keep) node.removeAttribute(attr.name);else {// 简单安全检查:href/src 避免 javascript:if ((attr.name === 'href' || attr.name === 'src') && /javascript:/i.test(attr.value)) {node.removeAttribute(attr.name);}}}// 递归清洗子节点for (let i = node.childNodes.length - 1; i >= 0; i--) walk(node.childNodes[i]);}for (let i = body.childNodes.length - 1; i >= 0; i--) walk(body.childNodes[i]);return body.innerHTML;
}// 示例用法
const html = '欢迎 点击 文本
';
const clean = sanitizeHtmlWithWhitelist(html, ['p','a','strong'], {'a': ['href']});
2.2 伪代码对比与实现要点
在上述实现中,节点类型判断、标签白名单校验、以及 属性清洗是核心环节;如果遇到 非白名单元素,应当以“移除节点但保留其子节点”的方式进行<强>展开,避免丢失文本信息。
另外,为了提升可维护性,可以把白名单和属性映射作为参数传入,方便在不同场景下进行扩展;这也是实现“有选择地保留指定标签”的重要设计点。
3. 第三方库与快速落地
除了自行实现之外,直接使用成熟库能显著提升稳定性与安全性,常用的选择是 DOMPurify 这样的库,它提供了可配置的白名单、属性白名单等功能。
通过集成库,可以在 前端快速落地,同时保证对 XSS 的防护更加成熟和全面。对于需要严格控制的应用,推荐结合库提供的配置项来实现精确的保留标签策略。
// 使用 DOMPurify 保留指定标签的示例
// dirty 为待清洗的 HTML 字符串
const clean = DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['b','i','em','strong','a'],ALLOWED_ATTR: ['href','title']
});


