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 標頭。

通常,該標頭會自動設定,並包含提出請求的頁面的網址。在大多數情況下,這根本不重要,有時出於安全目的,將其移除或縮短是有意義的。

referrer 選項允許設定任何 Referer(在當前來源內)或移除它。

若要傳送無引導,請設定一個空字串

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

若要在當前來源內設定另一個網址

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

referrerPolicy 選項設定 Referer 的一般規則。

要求分為 3 種類型

  1. 要求到相同來源。
  2. 要求到另一個來源。
  3. 從 HTTPS 要求到 HTTP(從安全到不安全協定)。

與允許設定確切 Referer 值的 referrer 選項不同,referrerPolicy 會告訴瀏覽器每個要求類型的通用規則。

可能的數值在 引導政策規範 中說明

  • "strict-origin-when-cross-origin" – 預設值:對於相同來源傳送完整的 Referer,對於跨來源僅傳送來源,除非是 HTTPS→HTTP 要求,則不傳送任何內容。
  • "no-referrer-when-downgrade" – 永遠傳送完整的 Referer,除非我們從 HTTPS 傳送要求到 HTTP(較不安全的協定)。
  • "no-referrer" – 永不傳送 Referer
  • "origin" – 僅在 Referer 中傳送來源,而非完整的頁面網址,例如僅傳送 http://site.com,而非 http://site.com/path
  • "origin-when-cross-origin" – 將完整的 Referer 傳送到相同來源,但僅將來源部分傳送到跨來源要求(如上所述)。
  • "same-origin" – 將完整的 Referer 傳送到相同來源,但沒有 Referer 傳送到跨來源要求。
  • "strict-origin" – 僅傳送來源,而非 HTTPS→HTTP 要求的 Referer
  • "unsafe-url" – 永遠在 Referer 中傳送完整的網址,即使是 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" 完整 完整 完整

假設我們有一個管理區域,其網址結構不應從網站外部得知。

如果我們傳送 fetch,則預設情況下,它總是會傳送包含我們頁面完整網址的 Referer 標頭(除非我們從 HTTPS 要求到 HTTP,則沒有 Referer)。

例如 Referer: https://javascriptinfo.dev.org.tw/admin/secret/paths

如果我們希望其他網站僅知道來源部分,而不是網址路徑,則可以設定選項

fetch('https://another.com/page', {
  // ...
  referrerPolicy: "origin-when-cross-origin" // Referer: https://javascriptinfo.dev.org.tw
});

我們可以將它放入所有 fetch 呼叫,也可以整合到專案的 JavaScript 函式庫中,該函式庫會執行所有要求並在其中使用 fetch

與預設行為唯一的不同點在於,對於其他來源的請求,fetch 只會傳送 URL 的來源部分(例如:https://javascriptinfo.dev.org.tw,不含路徑)。對於我們來源的請求,我們仍然會取得完整的 Referer(可能對除錯目的有用)。

Referrer 政策不只適用於 fetch

規格 中描述的 Referrer 政策不只適用於 fetch,而是更全面性的。

特別是,可以使用 Referrer-Policy HTTP 標頭為整個頁面設定預設政策,或使用 <a rel="noreferrer"> 為每個連結設定。

mode

mode 選項是一個安全防護措施,可防止偶發的跨來源請求

  • "cors" – 預設值,允許跨來源請求,如 Fetch:跨來源請求 中所述,
  • "same-origin" – 禁止跨來源請求,
  • "no-cors" – 僅允許安全的跨來源請求。

fetch 的 URL 來自第三方,而我們想要一個「電源開關」來限制跨來源功能時,此選項可能很有用。

credentials

credentials 選項指定 fetch 是否應隨請求傳送 Cookie 和 HTTP-Authorization 標頭。

  • "same-origin" – 預設值,不要對跨來源請求傳送,
  • "include" – 永遠傳送,需要跨來源伺服器的 Access-Control-Allow-Credentials 才能讓 JavaScript 存取回應,這在 Fetch:跨來源請求 章節中已涵蓋,
  • "omit" – 永不傳送,即使是同來源請求。

cache

預設情況下,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…)