2022 年 10 月 12 日

Fetch API

到目前为止,我们已经对 fetch 有了相当多的了解。

让我们看看 API 的其余部分,以涵盖它的所有功能。

请注意

请注意:这些选项中的大多数很少使用。您可以跳过本章,仍然可以很好地使用 fetch

不过,了解 fetch 的功能还是很好的,这样如果需要,您可以返回并阅读详细信息。

以下是所有可能的 fetch 选项及其默认值(注释中的替代方案)的完整列表

let promise = fetch(url, {
  method: "GET", // POST, PUT, DELETE, etc.
  headers: {
    // the content type header value is usually auto-set
    // depending on the request body
    "Content-Type": "text/plain;charset=UTF-8"
  },
  body: undefined, // string, FormData, Blob, BufferSource, or URLSearchParams
  referrer: "about:client", // or "" to send no Referer header,
  // or an url from the current origin
  referrerPolicy: "strict-origin-when-cross-origin", // no-referrer-when-downgrade, no-referrer, origin, same-origin...
  mode: "cors", // same-origin, no-cors
  credentials: "same-origin", // omit, include
  cache: "default", // no-store, reload, no-cache, force-cache, or only-if-cached
  redirect: "follow", // manual, error
  integrity: "", // a hash, like "sha256-abcdef1234567890"
  keepalive: false, // true
  signal: undefined, // AbortController to abort request
  window: window // null
});

令人印象深刻的列表,对吧?

我们在 Fetch 一章中完全涵盖了 methodheadersbody

signal 选项在 Fetch: Abort 中介绍。

现在让我们探索剩余的功能。

referrer,referrerPolicy

这些选项控制 fetch 如何设置 HTTP Referer 头。

通常,该头会自动设置,并包含发出请求的页面的 URL。在大多数情况下,它根本不重要,有时,出于安全目的,有必要删除或缩短它。

referrer 选项允许设置任何 Referer(在当前域内)或将其删除。

要发送无引用来源,请设置一个空字符串。

fetch('/page', {
  referrer: "" // no Referer header
});

要设置当前域内的另一个 URL。

fetch('/page', {
  // assuming we're on https://javascript.js.cn
  // we can set any Referer header, but only within the current origin
  referrer: "https://javascript.js.cn/anotherpage"
});

referrerPolicy 选项为 Referer 设置通用规则。

请求分为 3 种类型。

  1. 对同一域的请求。
  2. 对另一个域的请求。
  3. 从 HTTPS 到 HTTP 的请求(从安全协议到不安全协议)。

与允许设置精确 Referer 值的 referrer 选项不同,referrerPolicy 为每种请求类型告诉浏览器通用规则。

可能的取值在 Referrer Policy 规范 中描述。

  • "strict-origin-when-cross-origin" – 默认值:对于同一域,发送完整的 Referer;对于跨域,仅发送域,除非它是 HTTPS→HTTP 请求,则不发送任何内容。
  • "no-referrer-when-downgrade" – 始终发送完整的 Referer,除非我们从 HTTPS 发送请求到 HTTP(到安全性较低的协议)。
  • "no-referrer" – 从不发送 Referer
  • "origin" – 仅在 Referer 中发送域,而不是完整的页面 URL,例如,仅发送 http://site.com 而不是 http://site.com/path
  • "origin-when-cross-origin" – 对同一域发送完整的 Referer,但对于跨域请求仅发送域部分(如上所述)。
  • "same-origin" – 对同一域发送完整的 Referer,但对于跨域请求不发送 Referer
  • "strict-origin" – 仅发送域,对于 HTTPS→HTTP 请求不发送 Referer
  • "unsafe-url" – 始终在 Referer 中发送完整的 URL,即使对于 HTTPS→HTTP 请求也是如此。

以下表格列出了所有组合。

对同一域 对另一个域 HTTPS→HTTP
"no-referrer" - - -
"no-referrer-when-downgrade" 完整 完整 -
"origin"
"origin-when-cross-origin" 完整
"same-origin" 完整 - -
"strict-origin" -
"strict-origin-when-cross-origin"""(默认) 完整 -
"unsafe-url" 完整 完整 完整

假设我们有一个管理区域,其 URL 结构不应从网站外部得知。

如果我们发送 fetch,则默认情况下,它始终会发送带有我们页面完整 URL 的 Referer 标头(除非我们从 HTTPS 请求到 HTTP,则不发送 Referer)。

例如,Referer: https://javascript.js.cn/admin/secret/paths

如果我们希望其他网站只知道域部分,而不是 URL 路径,我们可以设置以下选项。

fetch('https://another.com/page', {
  // ...
  referrerPolicy: "origin-when-cross-origin" // Referer: https://javascript.js.cn
});

我们可以将其添加到所有 fetch 调用中,也许可以将其集成到我们项目的 JavaScript 库中,该库执行所有请求并在内部使用 fetch

与默认行为唯一的区别是,对于跨域请求,fetch 只发送 URL 的 origin 部分(例如 https://javascript.js.cn,不包含路径)。对于同源请求,我们仍然会获得完整的 Referer(可能对调试有用)。

Referrer 策略不仅仅适用于 fetch

Referrer 策略,在 规范 中描述,不仅仅适用于 fetch,而是更全局的。

特别是,可以使用 Referrer-Policy HTTP 头部为整个页面设置默认策略,或者使用 <a rel="noreferrer"> 为每个链接设置策略。

模式

mode 选项是一种安全措施,可以防止偶尔发生的跨域请求

  • "cors" – 默认值,允许跨域请求,如 Fetch:跨域请求 中所述,
  • "same-origin" – 禁止跨域请求,
  • "no-cors" – 只允许安全的跨域请求。

fetch 的 URL 来自第三方,并且我们想要一个“断电开关”来限制跨域功能时,此选项可能很有用。

凭据

credentials 选项指定 fetch 是否应该将 cookie 和 HTTP-Authorization 头部与请求一起发送。

  • "same-origin" – 默认值,不发送跨域请求,
  • "include" – 始终发送,需要跨域服务器的 Access-Control-Allow-Credentials,以便 JavaScript 访问响应,这在 Fetch:跨域请求 一章中介绍过,
  • "omit" – 从不发送,即使对于同源请求也是如此。

缓存

默认情况下,fetch 请求使用标准的 HTTP 缓存。也就是说,它尊重 ExpiresCache-Control 头部,发送 If-Modified-Since 等等。就像常规的 HTTP 请求一样。

cache 选项允许忽略 HTTP 缓存或微调其使用方式

  • "default"fetch 使用标准的 HTTP 缓存规则和头部,
  • "no-store" – 完全忽略 HTTP 缓存,如果我们设置 If-Modified-SinceIf-None-MatchIf-Unmodified-SinceIf-MatchIf-Range 头部,此模式将成为默认模式,
  • "reload" – 不从 HTTP 缓存(如果有)中获取结果,但使用响应填充缓存(如果响应头部允许此操作),
  • "no-cache" – 如果存在缓存响应,则创建条件请求,否则创建普通请求。使用响应填充 HTTP 缓存,
  • "force-cache" – 使用来自 HTTP 缓存的响应,即使它已过期。如果 HTTP 缓存中没有响应,则进行常规的 HTTP 请求,正常执行,
  • "only-if-cached" – 使用来自 HTTP 缓存的响应,即使它已过期。如果 HTTP 缓存中没有响应,则会报错。仅在 mode"same-origin" 时有效。

重定向

通常,fetch 会透明地遵循 HTTP 重定向,例如 301、302 等。

redirect 选项允许更改此行为。

  • "follow" – 默认值,遵循 HTTP 重定向。
  • "error" – 在发生 HTTP 重定向时报错。
  • "manual" – 允许手动处理 HTTP 重定向。在发生重定向的情况下,我们将获得一个特殊的响应对象,其中 response.type="opaqueredirect" 且状态和其他大多数属性为零或为空。

完整性

integrity 选项允许检查响应是否与预先知道的校验和匹配。

规范 中所述,支持的哈希函数为 SHA-256、SHA-384 和 SHA-512,根据浏览器可能还有其他函数。

例如,我们正在下载一个文件,并且知道它的 SHA-256 校验和为“abcdef”(当然,实际的校验和更长)。

我们可以将其放在 integrity 选项中,如下所示

fetch('http://site.com/file', {
  integrity: 'sha256-abcdef'
});

然后 fetch 将自行计算 SHA-256 并将其与我们的字符串进行比较。如果发生不匹配,则会触发错误。

保持活动

keepalive 选项表示请求可能“超出”发起它的网页的生命周期。

例如,我们收集有关当前访问者如何使用我们页面的统计信息(鼠标点击、他查看的页面片段),以分析和改进用户体验。

当访问者离开我们的页面时,我们希望将数据保存到我们的服务器。

我们可以使用 window.onunload 事件来实现这一点。

window.onunload = function() {
  fetch('/analytics', {
    method: 'POST',
    body: "statistics",
    keepalive: true
  });
};

通常,当文档卸载时,所有关联的网络请求都会被中止。但是 keepalive 选项告诉浏览器即使在离开页面后也要在后台执行请求。因此,此选项对于我们的请求成功至关重要。

它有一些限制。

  • 我们不能发送兆字节:keepalive 请求的正文限制为 64KB。
    • 如果我们需要收集大量有关访问的统计信息,我们应该定期以数据包的形式将其发送出去,这样最后一次 onunload 请求就不会剩下太多数据。
    • 此限制适用于所有 keepalive 请求。换句话说,我们可以并行执行多个 keepalive 请求,但它们的正文长度总和不应超过 64KB。
  • 如果文档已卸载,我们无法处理服务器响应。因此,在我们的示例中,fetch 将由于 keepalive 而成功,但后续函数将无法工作。
    • 在大多数情况下,例如发送统计信息,这不是问题,因为服务器只是接受数据,通常会向此类请求发送空响应。
教程地图

评论

在评论之前请阅读...
  • 如果您有任何改进建议,请提交 GitHub 问题或拉取请求,而不是评论。
  • 如果您无法理解文章中的某些内容,请详细说明。
  • 要插入少量代码,请使用<code>标签,对于多行代码,请使用<pre>标签,对于超过10行的代码,请使用沙盒(plnkrjsbincodepen…)