react学习7:如何渲染html字符串

105 阅读2分钟

在 React 中,直接渲染用户输入的 HTML 字符串时,React 默认会将所有内容视为纯文本进行转义,以防止 XSS(跨站脚本)攻击。

如果要渲染用户输入的 HTML 文本,需要使用 dangerouslySetInnerHTML 属性,这是 React 提供的专门用于插入原始 HTML 的方式。

function HtmlRenderer({ userInputHtml }) { 
    // 创建一个包含 __html 属性的对象 
    const content = { __html: userInputHtml }; 
    // 使用 dangerouslySetInnerHTML 渲染 
    return <div dangerouslySetInnerHTML={content} />; 
} 
    
// 使用组件 
<HtmlRenderer userInputHtml="<p>这是用户输入的<strong>HTML</strong>内容</p>" />

React 会将 dangerouslySetInnerHTML 接收的对象中的 __html 属性值当作原始 HTML 处理, 直接将其插入到 DOM 中,而不进行任何转义。

在 Vue 中处理用户输入的 HTML 文本与 React 类似,但提供了更直接的指令方式:

image.png

  • Vue 默认会对模板中的文本进行转义(如将 < 转为 &lt;),防止 XSS 攻击
  • 使用 v-html 时,Vue 会跳过转义过程,直接将内容作为 HTML 插入到 DOM 中

在默认情况下,无论是 React 还是 Vue,当你直接传递一个包含 HTML 标签的字符串时,框架都会将其视为纯文本进行处理, 即对 HTML 特殊字符(如 <>& 等)进行转义,最终在页面上显示的是字符串本身,而不是解析后的 HTML 元素。

举个例子,如果你传递字符串 <strong>Hello</strong>,默认情况下,页面会显示 <strong>Hello</strong> 这段文本(包括尖括号和标签名),而不会显示加粗的 "Hello"。

这种行为是框架的安全设计,目的是防止 XSS(跨站脚本)攻击。如果框架默认直接解析 HTML 字符串,攻击者可能会注入恶意脚本(如 <script>窃取信息</script>),从而获得用户数据或控制页面。

如果非要使用v-html或者dangerouslySetInnerHTML, 比如下面代码:

const testHtml = '<div style="color:red;" onclick="alert(\'123\')"><p>123</p></div>'
// 在P标签直接使用
<p  dangerouslySetInnerHTML={{ __html: testHtml}} ></p>

此时,就会执行alert(\'123\')

因此,需要用 DOMPurify 等工具净化 HTML,覆盖所有风险场景:

import DOMPurify from 'dompurify';
const testHtml = DOMPurify.sanitize(
    '<div style="color:red;" onclick="alert(\'123\')"><p>123</p></div>'
)

image.png

但是,这么一段代码不会执行打印语句:

<p dangerouslySetInnerHTML={{ __html: '<div style="color:red;"><p>123</p><script>console.log("1111")</script></div>', }} ></p>

这是因为现代浏览器会默认阻止通过 动态插入 的 <script> 标签执行脚本,这是浏览器层面的安全防护措施。

即使没有使用净化库,浏览器也会做基础防护。