Document: write() 方法

已弃用:此特性不再推荐。虽然某些浏览器可能仍然支持它,但它可能已经从相关的网络标准中删除,可能正在删除过程中,或者可能仅为兼容性目的而保留。请避免使用它,如果可能,请更新现有代码;请参阅本页底部的兼容性表格以指导您的决策。请注意,此特性可能随时停止工作。

警告:强烈不建议使用 document.write() 方法。请避免使用它,并尽可能在现有代码中替换它。

正如 HTML 规范本身所警告的

此方法具有非常特殊的行为。在某些情况下,此方法可以在解析器运行时影响 HTML 解析器 的状态,从而导致 DOM 不对应于文档的源代码(例如,如果写入的字符串是字符串 "<plaintext>" 或 "<!--")。在其他情况下,此调用可能会首先清除当前页面,就像调用了 document.open() 一样。在更多情况下,此方法被简单地忽略,或抛出异常。用户代理 明确允许避免执行通过此方法插入的 script 元素。更糟糕的是,此方法的精确行为在某些情况下可能取决于网络延迟,这可能导致非常难以调试的故障。出于所有这些原因,强烈不建议使用此方法。

警告:此方法将其输入解析为 HTML,并将结果写入 DOM。此类 API 被称为 注入槽,如果输入最初来自攻击者,则可能成为 跨站点脚本 (XSS) 攻击的载体。

您可以通过始终传递 TrustedHTML 对象而不是字符串并 强制执行可信类型 来缓解此风险。有关更多信息,请参阅 安全注意事项

Document 接口的 write() 方法将一个或多个 TrustedHTML 或字符串参数中的文本写入通过 document.open() 打开的文档流。

语法

js
write(markup)
write(markup, markup2)
write(markup, markup2, /* …, */ markupN)

参数

markup, …, markupN

TrustedHTML 对象或包含要写入文档的标记的字符串。

返回值

无(undefined)。

异常

InvalidStateError DOMException

在 XML 文档上调用了该方法,或者在解析器当前正在执行自定义元素构造函数时调用了该方法。

TypeError

强制执行可信类型 并且 没有定义默认策略 来创建 TrustedHTML 对象时,字符串作为其中一个参数传递。

描述

document.write() 将作为参数传递的对象的标记文本按照参数指定的顺序解析到打开文档的对象模型 (DOM) 中。

由于 document.write() 写入到文档,因此在关闭(已加载)文档上调用 document.write()(而未首先调用 document.open())会自动调用 document.open(),这将清除文档。

例外情况是,如果 document.write() 调用嵌入在内联 HTML <script> 标签中,则它不会自动调用 document.open()

html
<script>
  document.write("<h1>Main title</h1>");
</script>

document.write() (和 document.writeln) 不能与 XML 或 XHTML 一起使用,尝试这样做将抛出 InvalidStateError 异常。如果打开带有 .xhtml 文件扩展名的本地文件,或对于任何带有 application/xhtml+xml MIME 类型服务的文档,情况都是如此。更多信息可在 W3C XHTML FAQ 中找到。

延迟异步 脚本中使用 document.write() 将被忽略,并且您将在错误控制台中收到类似“来自异步加载的外部脚本的 document.write() 调用被忽略”的消息。

仅在 Edge 中,在 <iframe> 中多次调用 document.write() 会导致错误“SCRIPT70: 权限被拒绝”。

安全注意事项

该方法是 跨站脚本 (XSS) 攻击的潜在途径,其中用户提供的潜在不安全字符串在未首先进行清理的情况下被注入到 DOM 中。虽然该方法可能会阻止 <script> 元素在某些浏览器中被注入时执行(有关 Chrome 的信息,请参阅 Intervening against document.write()),但它容易受到攻击者精心构造 HTML 以运行恶意 JavaScript 的许多其他方式的影响。

您可以通过始终传递 TrustedHTML 对象而不是字符串,并使用 require-trusted-types-for CSP 指令强制执行可信类型 来缓解这些问题。这确保了输入通过转换函数,该函数有机会清理输入以删除潜在危险的标记(例如 <script> 元素和事件处理程序属性),然后再注入。

示例

写入 TrustedHTML

此示例使用 Trusted Types API 在将 HTML 字符串写入文档之前清理其中的 <script> 元素。

该示例最初显示一些默认文本和一个按钮。当点击按钮时,当前文档将被打开,三个 HTML 字符串被转换为 TrustedHTML 实例并写入文档,然后文档被关闭。这替换了示例框架中的文档,包括按钮的原始 HTML 和执行更新的 JavaScript!

HTML

html
<p>Some original document content.</p>
<button id="replace" type="button">Replace document content</button>

JavaScript

首先,我们使用 Window.trustedTypes 属性访问全局 TrustedTypePolicyFactory,并使用其 createPolicy() 方法定义名为 "docPolicy" 的策略。

新策略定义了一个转换函数 createHTML(),用于创建我们将传递给 write() 方法的 TrustedHTML 对象。此方法可以随意处理输入字符串:可信类型 API 只要求您通过策略转换函数传递输入,而不是要求转换函数执行任何特定操作。

您可以使用该方法通过删除潜在不安全的功能(例如 <script> 标签或事件处理程序属性)来清理输入。清理很难做好,因此此过程通常使用信誉良好的第三方库,例如 DOMPurify

出于演示目的,我们在此实现一个简陋的“清理器”,它将脚本开始和结束标签中的 < 符号替换为 &lt; 字符。

js
const policy = trustedTypes.createPolicy("docPolicy", {
  createHTML(string) {
    return string
      .replace("<script", "&lt;script")
      .replace("</script", "&lt;/script");
  },
});

然后,我们可以对返回的策略使用 TrustedTypePolicy.createHTML() 方法,从原始输入字符串创建 TrustedHTML 对象。当用户点击按钮时,这些对象会传递给 write() 函数。

js
const oneInput = "<h1>Out with the old</h1>";
const twoInput = "<p>in with the new!</p>";
const threeInput = "<script>alert('evil afoot')<" + "/script>";
const replace = document.querySelector("#replace");

replace.addEventListener("click", () => {
  document.open();
  document.write(
    policy.createHTML(oneInput),
    policy.createHTML(twoInput),
    policy.createHTML(threeInput),
  );
  document.close();
});

结果

按下按钮并注意,我们信任(在此示例中)的 HTML 元素被注入,但不受信任的 <script> 元素现在以纯文本形式呈现。

写入字符串

这与前面的示例相同,只是未使用或强制执行可信类型。我们正在写入未清理的字符串,这可能为 XSS 攻击 提供途径。

此示例最初显示一些默认文本和一个按钮。当点击按钮时,当前文档将被打开,三个 HTML 字符串被写入文档,然后文档被关闭。这替换了示例框架中的文档,包括按钮的原始 HTML 和执行更新的 JavaScript。

HTML

html
<p>Some original document content.</p>
<button id="replace" type="button">Replace document content</button>

JavaScript

js
const replace = document.querySelector("#replace");

const oneInput = "<h1>Out with the old</h1>";
const twoInput = "<p>in with the new!</p>";
const threeInput = "<script>alert('evil afoot')<" + "/script>";

replace.addEventListener("click", () => {
  document.open();
  document.write(oneInput, twoInput, threeInput);
  document.close();
});

结果

按下按钮,并注意所有 HTML 元素都被注入。这包括 <script> 元素,它在实际应用程序中可能会执行有害代码。

规范

规范
HTML
# dom-document-write-dev

浏览器兼容性

另见