Javascript Fetch API

2023-02-17 10:57 更新

到目前為止,我們已經對 ?fetch? 相當了解了。

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

請注意:

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

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

這是所有可能的 fetch 選項及其默認值(注釋中標注了可選值)的完整列表:

let promise = fetch(url, {
  method: "GET", // POST,PUT,DELETE,等。
  headers: {
    // 內容類型 header 值通常是自動設置的
    // 取決于 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,
  // 或者是當前源的 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: "", // 一個 hash,像 "sha256-abcdef1234567890"
  keepalive: false, // true
  signal: undefined, // AbortController 來中止請求
  window: window // null
});

一個令人印象深刻的列表,對吧?

我們已經在 Fetch 一章中詳細介紹了 method,headers 和 body

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

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

referrer,referrerPolicy

這些選項決定了 fetch 如何設置 HTTP 的 Referer header。

通常來說,這個 header 是被自動設置的,并包含了發(fā)出請求的頁面的 url。在大多數情況下,它一點也不重要,但有時出于安全考慮,刪除或縮短它是有意義的。

referrer 選項允許設置任何 Referer(在當前域的),或者移除它。

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

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

設置在當前域內的另一個 url:

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

referrerPolicy 選項為 Referer 設置一般的規(guī)則。

請求分為 3 種類型:

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

與 referrer 選項允許設置確切的 Referer 值不同,referrerPolicy 告訴瀏覽器針對各個請求類型的一般的規(guī)則。

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

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

這是一個包含所有組合的表格:

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

假如我們有一個帶有 URL 結構的管理區(qū)域(admin zone),它不應該被從網站外看到。

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

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

如果我們想讓其他網站只知道域的部分,而不是 URL 路徑,我們可以這樣設置選項:

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

我們可以將其置于所有 fetch 調用中,也可以將其集成到我們項目的執(zhí)行所有請求并在內部使用 fetch 的 JavaScript 庫中。

與默認行為相比,它的唯一區(qū)別在于,對于跨源請求,fetch 只發(fā)送 URL 域的部分(例如 https://javascript.info,沒有路徑)。對于同源請求,我們仍然可以獲得完整的 Referer(可能對于調試目的是有用的)。

Referrer policy 不僅適用于 ?fetch?

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

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

mode

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

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

當 fetch 的 URL 來自于第三方,并且我們想要一個“斷電開關”來限制跨源能力時,此選項可能很有用。

credentials

credentials 選項指定 fetch 是否應該隨請求發(fā)送 cookie 和 HTTP-Authorization header。

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

cache

默認情況下,fetch 請求使用標準的 HTTP 緩存。就是說,它遵從 Expires,Cache-Control header,發(fā)送 If-Modified-Since,等。就像常規(guī)的 HTTP 請求那樣。

使用 cache 選項可以忽略 HTTP 緩存或者對其用法進行微調:

  • ?"default"? —— ?fetch? 使用標準的 HTTP 緩存規(guī)則和 header,
  • ?"no-store"? —— 完全忽略 HTTP 緩存,如果我們設置 header ?If-Modified-Since?,?If-None-Match?,?If-Unmodified-Since?,?If-Match?,或 ?If-Range?,則此模式會成為默認模式,
  • ?"reload"? —— 不從 HTTP 緩存中獲取結果(如果有),而是使用響應填充緩存(如果 response header 允許此操作),
  • ?"no-cache"? —— 如果有一個已緩存的響應,則創(chuàng)建一個有條件的請求,否則創(chuàng)建一個普通的請求。使用響應填充 HTTP 緩存,
  • ?"force-cache"? —— 使用來自 HTTP 緩存的響應,即使該響應已過時(stale)。如果 HTTP 緩存中沒有響應,則創(chuàng)建一個常規(guī)的 HTTP 請求,行為像正常那樣,
  • ?"only-if-cached"? —— 使用來自 HTTP 緩存的響應,即使該響應已過時(stale)。如果 HTTP 緩存中沒有響應,則報錯。只有當 ?mode? 為 ?same-origin? 時生效。

redirect

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

redirect 選項允許對此進行更改:

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

integrity

integrity 選項允許檢查響應是否與已知的預先校驗和相匹配。

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

例如,我們下載一個文件,并且我們知道它的 SHA-256 校驗和為 “abcdef”(當然,實際校驗和會更長)。

我們可以將其放在 integrity 選項中,就像這樣:

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

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

keepalive

keepalive 選項表示該請求可能會在網頁關閉后繼續(xù)存在。

例如,我們收集有關當前訪問者是如何使用我們的頁面(鼠標點擊,他查看的頁面片段)的統(tǒng)計信息,以分析和改善用戶體驗。

當訪問者離開我們的網頁時 —— 我們希望能夠將數據保存到我們的服務器上。

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

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

通常,當一個文檔被卸載時(unloaded),所有相關的網絡請求都會被中止。但是,keepalive 選項告訴瀏覽器,即使在離開頁面后,也要在后臺執(zhí)行請求。所以,此選項對于我們的請求成功至關重要。

它有一些限制:

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


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號