You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中何时使用dangerouslySetInnerHTML?相关疑问解答

关于React中dangerouslySetInnerHTML的解析与替代方案

一、为什么它叫“dangerous”?

React默认会自动转义所有插入到JSX里的文本——比如你写<div>{'<script>恶意代码</script>'}</div>,React会把尖括号转成实体字符,最终页面只会显示这段文本,不会执行脚本。但dangerouslySetInnerHTML会跳过这个转义流程,直接把传入的HTML字符串渲染成真实DOM节点。

如果这段HTML来自不可信来源(比如用户输入、未过滤的第三方接口数据),攻击者可以注入恶意脚本,窃取用户Cookie、篡改页面内容甚至发起钓鱼攻击。名字里的“dangerous”就是React团队给开发者的强提醒:这个属性有XSS风险,必须谨慎使用。

二、什么时候该用它?

只有在你能100%确保要渲染的HTML内容是安全可信的情况下才用:

  • 后端返回的、经过严格XSS过滤/清洗的富文本(比如后台编辑器生成的内容,已经剔除了所有恶意标签和脚本)
  • 你自己硬编码的固定HTML片段,完全没有外部输入的部分

三、工作原理

它是React提供的特殊属性,必须接收一个包含__html键的对象,值就是要渲染的HTML字符串。React会直接把这段HTML解析并插入到对应DOM节点中,跳过常规的JSX转义逻辑。示例:

function TrustedContent() {
  // 假设这是后端返回的已过滤富文本
  const safeHtml = "<p>这是经过安全处理的<b>加粗文本</b></p>";
  return <div dangerouslySetInnerHTML={{ __html: safeHtml }} />;
}

四、针对你的问答网站的替代方案

如果你的问题卡片内容是结构化的(比如题目里的加粗、列表、公式等),完全可以不用dangerouslySetInnerHTML,推荐这几种更安全的方式:

1. 用JSX直接构建结构化内容

如果题目格式固定,把内容拆成JSX元素来渲染,完全规避HTML注入风险:

function QuestionCard({ question }) {
  // 假设question是包含结构化字段的对象
  return (
    <div className="question-card">
      <h3>{question.title}</h3>
      <p>
        {question.content.normalText}
        {question.content.highlightText && <b>{question.content.highlightText}</b>}
      </p>
      <ul>
        {question.options.map(opt => (
          <li key={opt.id}>{opt.text}</li>
        ))}
      </ul>
    </div>
  );
}

2. 使用富文本解析库

如果需要支持复杂格式(比如Markdown、轻量富文本),用专门的库把格式文本转成安全的JSX:

  • 若内容是Markdown格式,用react-markdown直接渲染:
import ReactMarkdown from 'react-markdown';

function QuestionCard({ questionMarkdown }) {
  return (
    <div className="question-card">
      <ReactMarkdown>{questionMarkdown}</ReactMarkdown>
    </div>
  );
}
  • 若必须处理HTML,先用sanitize-html过滤恶意内容,再结合dangerouslySetInnerHTML使用:
import sanitizeHtml from 'sanitize-html';

function QuestionCard({ rawHtml }) {
  const cleanHtml = sanitizeHtml(rawHtml, {
    allowedTags: ['b', 'i', 'p', 'ul', 'li'], // 只允许指定安全标签
    allowedAttributes: {} // 禁止所有属性,避免脚本注入
  });
  return <div dangerouslySetInnerHTML={{ __html: cleanHtml }} />;
}

3. 封装自定义格式组件

把常用的格式(加粗、引用、代码块)封装成React组件,通过结构化数据驱动渲染:

function Bold({ children }) {
  return <b>{children}</b>;
}

function QuestionCard({ questionSegments }) {
  return (
    <div className="question-card">
      {questionSegments.map((seg, idx) => {
        switch(seg.type) {
          case 'text': return <span key={idx}>{seg.content}</span>;
          case 'bold': return <Bold key={idx}>{seg.content}</Bold>;
          case 'list': return (
            <ul key={idx}>
              {seg.items.map((item, i) => <li key={i}>{item}</li>)}
            </ul>
          );
          default: return null;
        }
      })}
    </div>
  );
}

内容的提问来源于stack exchange,提问作者Gire Munga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 17:25:02