Javascript Fetch API

2023-02-17 10:57 更新

到目前為止,我們已經(jīng)對(duì) ?fetch? 相當(dāng)了解了。

現(xiàn)在讓我們來(lái)看看 fetch 的剩余 API,來(lái)了解它的全部本領(lǐng)吧。

請(qǐng)注意:

請(qǐng)注意:這些選項(xiàng) (option) 大多都很少使用。即使跳過(guò)本章,你也可以很好地使用 fetch

但是,知道 fetch 可以做什么還是很好的,所以如果需要,你可以來(lái)看看這些細(xì)節(jié)內(nèi)容。

這是所有可能的 fetch 選項(xiàng)及其默認(rèn)值(注釋中標(biāo)注了可選值)的完整列表:

let promise = fetch(url, {
  method: "GET", // POST,PUT,DELETE,等。
  headers: {
    // 內(nèi)容類型 header 值通常是自動(dòng)設(shè)置的
    // 取決于 request body
    "Content-Type": "text/plain;charset=UTF-8"
  },
  body: undefined // string,F(xiàn)ormData,Blob,BufferSource,或 URLSearchParams
  referrer: "about:client", // 或 "" 以不發(fā)送 Referer header,
  // 或者是當(dāng)前源的 url
  referrerPolicy: "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,或 only-if-cached
  redirect: "follow", // manual,error
  integrity: "", // 一個(gè) hash,像 "sha256-abcdef1234567890"
  keepalive: false, // true
  signal: undefined, // AbortController 來(lái)中止請(qǐng)求
  window: window // null
});

一個(gè)令人印象深刻的列表,對(duì)吧?

我們已經(jīng)在 Fetch 一章中詳細(xì)介紹了 method,headers 和 body。

在 Fetch:中止(Abort) 一章中介紹了 signal 選項(xiàng)。

現(xiàn)在讓我們一起探索其余的功能。

referrer,referrerPolicy

這些選項(xiàng)決定了 fetch 如何設(shè)置 HTTP 的 Referer header。

通常來(lái)說(shuō),這個(gè) header 是被自動(dòng)設(shè)置的,并包含了發(fā)出請(qǐng)求的頁(yè)面的 url。在大多數(shù)情況下,它一點(diǎn)也不重要,但有時(shí)出于安全考慮,刪除或縮短它是有意義的。

referrer 選項(xiàng)允許設(shè)置任何 Referer(在當(dāng)前域的),或者移除它。

如果不想發(fā)送 referrer,可以將 referrer 設(shè)置為空字符串:

fetch('/page', {
  referrer: "" // 沒(méi)有 Referer header
});

設(shè)置在當(dāng)前域內(nèi)的另一個(gè) url:

fetch('/page', {
  // 假設(shè)我們?cè)?https://javascript.info
  // 我們可以設(shè)置任何 Referer header,但必須是在當(dāng)前域內(nèi)的
  referrer: "https://javascript.info/anotherpage"
});

referrerPolicy 選項(xiàng)為 Referer 設(shè)置一般的規(guī)則。

請(qǐng)求分為 3 種類型:

  1. 同源請(qǐng)求。
  2. 跨源請(qǐng)求。
  3. 從 HTTPS 到 HTTP 的請(qǐng)求 (從安全協(xié)議到不安全協(xié)議)。

與 referrer 選項(xiàng)允許設(shè)置確切的 Referer 值不同,referrerPolicy 告訴瀏覽器針對(duì)各個(gè)請(qǐng)求類型的一般的規(guī)則。

可能的值在 Referrer Policy 規(guī)范中有詳細(xì)描述:

  • ?"no-referrer-when-downgrade"? —— 默認(rèn)值:除非我們從 HTTPS 發(fā)送請(qǐng)求到 HTTP(到安全性較低的協(xié)議),否則始終會(huì)發(fā)送完整的 ?Referer?。
  • ?"no-referrer"? —— 從不發(fā)送 ?Referer?。
  • ?"origin"? —— 只發(fā)送在 ?Referer? 中的域,而不是完整的頁(yè)面 URL,例如,只發(fā)送 ?http://site.com? 而不是 ?http://site.com/path?。
  • ?"origin-when-cross-origin"? —— 發(fā)送完整的 ?Referer? 到相同的源,但對(duì)于跨源請(qǐng)求,只發(fā)送域部分(同上)。
  • ?"same-origin"? —— 發(fā)送完整的 ?Referer? 到相同的源,但對(duì)于跨源請(qǐng)求,不發(fā)送 ?Referer?。
  • ?"strict-origin"? —— 只發(fā)送域,對(duì)于 HTTPS→HTTP 請(qǐng)求,則不發(fā)送 ?Referer?。
  • ?"strict-origin-when-cross-origin"? —— 對(duì)于同源情況下則發(fā)送完整的 ?Referer?,對(duì)于跨源情況下,則只發(fā)送域,如果是 HTTPS→HTTP 請(qǐng)求,則什么都不發(fā)送。
  • ?"unsafe-url"? —— 在 ?Referer? 中始終發(fā)送完整的 url,即使是 HTTPS→HTTP 請(qǐng)求。

這是一個(gè)包含所有組合的表格:

同源 跨源 HTTPS→HTTP
"no-referrer" - - -
"no-referrer-when-downgrade" 或 ""(默認(rèn)) 完整的 url 完整的 url -
"origin" 僅域 僅域 僅域
"origin-when-cross-origin" 完整的 url 僅域 僅域
"same-origin" 完整的 url - -
"strict-origin" 僅域 僅域 -
"strict-origin-when-cross-origin" 完整的 url 僅域 -
"unsafe-url" 完整的 url 完整的 url 完整的 url

假如我們有一個(gè)帶有 URL 結(jié)構(gòu)的管理區(qū)域(admin zone),它不應(yīng)該被從網(wǎng)站外看到。

如果我們發(fā)送了一個(gè) fetch,則默認(rèn)情況下,它總是發(fā)送帶有頁(yè)面完整 url 的 Referer header(我們從 HTTPS 向 HTTP 發(fā)送請(qǐng)求的情況除外,這種情況下沒(méi)有 Referer)。

例如 Referer: https://javascript.info/admin/secret/paths。

如果我們想讓其他網(wǎng)站只知道域的部分,而不是 URL 路徑,我們可以這樣設(shè)置選項(xiàng):

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

我們可以將其置于所有 fetch 調(diào)用中,也可以將其集成到我們項(xiàng)目的執(zhí)行所有請(qǐng)求并在內(nèi)部使用 fetch 的 JavaScript 庫(kù)中。

與默認(rèn)行為相比,它的唯一區(qū)別在于,對(duì)于跨源請(qǐng)求,fetch 只發(fā)送 URL 域的部分(例如 https://javascript.info,沒(méi)有路徑)。對(duì)于同源請(qǐng)求,我們?nèi)匀豢梢垣@得完整的 Referer(可能對(duì)于調(diào)試目的是有用的)。

Referrer policy 不僅適用于 ?fetch?

在 規(guī)范 中描述的 referrer policy,不僅適用于 fetch,它還具有全局性。

特別是,可以使用 Referrer-Policy HTTP header,或者為每個(gè)鏈接設(shè)置 <a rel="noreferrer">,來(lái)為整個(gè)頁(yè)面設(shè)置默認(rèn)策略(policy)。

mode

mode 選項(xiàng)是一種安全措施,可以防止偶發(fā)的跨源請(qǐng)求:

  • ?"cors"? —— 默認(rèn)值,允許跨源請(qǐng)求,如 Fetch:跨源請(qǐng)求 一章所述,
  • ?"same-origin"? —— 禁止跨源請(qǐng)求,
  • ?"no-cors"? —— 只允許安全的跨源請(qǐng)求。

當(dāng) fetch 的 URL 來(lái)自于第三方,并且我們想要一個(gè)“斷電開(kāi)關(guān)”來(lái)限制跨源能力時(shí),此選項(xiàng)可能很有用。

credentials

credentials 選項(xiàng)指定 fetch 是否應(yīng)該隨請(qǐng)求發(fā)送 cookie 和 HTTP-Authorization header。

  • ?"same-origin"? —— 默認(rèn)值,對(duì)于跨源請(qǐng)求不發(fā)送,
  • ?"include"? —— 總是發(fā)送,需要來(lái)自跨源服務(wù)器的 ?Access-Control-Allow-Credentials?,才能使 JavaScript 能夠訪問(wèn)響應(yīng),詳細(xì)內(nèi)容在 Fetch:跨源請(qǐng)求 一章有詳細(xì)介紹,
  • ?"omit"? —— 不發(fā)送,即使對(duì)于同源請(qǐng)求。

cache

默認(rèn)情況下,fetch 請(qǐng)求使用標(biāo)準(zhǔn)的 HTTP 緩存。就是說(shuō),它遵從 Expires,Cache-Control header,發(fā)送 If-Modified-Since,等。就像常規(guī)的 HTTP 請(qǐng)求那樣。

使用 cache 選項(xiàng)可以忽略 HTTP 緩存或者對(duì)其用法進(jìn)行微調(diào):

  • ?"default"? —— ?fetch? 使用標(biāo)準(zhǔn)的 HTTP 緩存規(guī)則和 header,
  • ?"no-store"? —— 完全忽略 HTTP 緩存,如果我們?cè)O(shè)置 header ?If-Modified-Since?,?If-None-Match?,?If-Unmodified-Since?,?If-Match?,或 ?If-Range?,則此模式會(huì)成為默認(rèn)模式,
  • ?"reload"? —— 不從 HTTP 緩存中獲取結(jié)果(如果有),而是使用響應(yīng)填充緩存(如果 response header 允許此操作),
  • ?"no-cache"? —— 如果有一個(gè)已緩存的響應(yīng),則創(chuàng)建一個(gè)有條件的請(qǐng)求,否則創(chuàng)建一個(gè)普通的請(qǐng)求。使用響應(yīng)填充 HTTP 緩存,
  • ?"force-cache"? —— 使用來(lái)自 HTTP 緩存的響應(yīng),即使該響應(yīng)已過(guò)時(shí)(stale)。如果 HTTP 緩存中沒(méi)有響應(yīng),則創(chuàng)建一個(gè)常規(guī)的 HTTP 請(qǐng)求,行為像正常那樣,
  • ?"only-if-cached"? —— 使用來(lái)自 HTTP 緩存的響應(yīng),即使該響應(yīng)已過(guò)時(shí)(stale)。如果 HTTP 緩存中沒(méi)有響應(yīng),則報(bào)錯(cuò)。只有當(dāng) ?mode? 為 ?same-origin? 時(shí)生效。

redirect

通常來(lái)說(shuō),fetch 透明地遵循 HTTP 重定向,例如 301,302 等。

redirect 選項(xiàng)允許對(duì)此進(jìn)行更改:

  • ?"follow"? —— 默認(rèn)值,遵循 HTTP 重定向,
  • ?"error"? —— HTTP 重定向時(shí)報(bào)錯(cuò),
  • ?"manual"? —— 允許手動(dòng)處理 HTTP 重定向。在重定向的情況下,我們將獲得一個(gè)特殊的響應(yīng)對(duì)象,其中包含 ?response.type="opaqueredirect"? 和歸零/空狀態(tài)以及大多數(shù)其他屬性。

integrity

integrity 選項(xiàng)允許檢查響應(yīng)是否與已知的預(yù)先校驗(yàn)和相匹配。

正如 規(guī)范 所描述的,支持的哈希函數(shù)有 SHA-256,SHA-384,和 SHA-512,可能還有其他的,這取決于瀏覽器。

例如,我們下載一個(gè)文件,并且我們知道它的 SHA-256 校驗(yàn)和為 “abcdef”(當(dāng)然,實(shí)際校驗(yàn)和會(huì)更長(zhǎng))。

我們可以將其放在 integrity 選項(xiàng)中,就像這樣:

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

然后 fetch 將自行計(jì)算 SHA-256 并將其與我們的字符串進(jìn)行比較。如果不匹配,則會(huì)觸發(fā)錯(cuò)誤。

keepalive

keepalive 選項(xiàng)表示該請(qǐng)求可能會(huì)在網(wǎng)頁(yè)關(guān)閉后繼續(xù)存在。

例如,我們收集有關(guān)當(dāng)前訪問(wèn)者是如何使用我們的頁(yè)面(鼠標(biāo)點(diǎn)擊,他查看的頁(yè)面片段)的統(tǒng)計(jì)信息,以分析和改善用戶體驗(yàn)。

當(dāng)訪問(wèn)者離開(kāi)我們的網(wǎng)頁(yè)時(shí) —— 我們希望能夠?qū)?shù)據(jù)保存到我們的服務(wù)器上。

我們可以使用 window.onunload 事件來(lái)實(shí)現(xiàn):

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

通常,當(dāng)一個(gè)文檔被卸載時(shí)(unloaded),所有相關(guān)的網(wǎng)絡(luò)請(qǐng)求都會(huì)被中止。但是,keepalive 選項(xiàng)告訴瀏覽器,即使在離開(kāi)頁(yè)面后,也要在后臺(tái)執(zhí)行請(qǐng)求。所以,此選項(xiàng)對(duì)于我們的請(qǐng)求成功至關(guān)重要。

它有一些限制:

  • 我們無(wú)法發(fā)送兆字節(jié)的數(shù)據(jù):?keepalive? 請(qǐng)求的 body 限制為 64KB。
    • 如果我們需要收集有關(guān)訪問(wèn)的大量統(tǒng)計(jì)信息,我們則應(yīng)該將其定期以數(shù)據(jù)包的形式發(fā)送出去,這樣就不會(huì)留下太多數(shù)據(jù)給最后的 ?onunload? 請(qǐng)求了。
    • 此限制是被應(yīng)用于當(dāng)前所有 ?keepalive? 請(qǐng)求的總和的。換句話說(shuō),我們可以并行執(zhí)行多個(gè) ?keepalive? 請(qǐng)求,但它們的 body 長(zhǎng)度之和不得超過(guò) 64KB。
  • 如果文檔(document)已卸載(unloaded),我們就無(wú)法處理服務(wù)器響應(yīng)。因此,在我們的示例中,因?yàn)?nbsp;?keepalive?,所以 ?fetch? 會(huì)成功,但是后續(xù)的函數(shù)將無(wú)法正常工作。
    • 在大多數(shù)情況下,例如發(fā)送統(tǒng)計(jì)信息,這不是問(wèn)題,因?yàn)榉?wù)器只接收數(shù)據(jù),并通常向此類請(qǐng)求發(fā)送空的響應(yīng)。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)