fetch學習總結

背景

最近,react 項目,使用 fetch 來進行 http 請求。遇到的問題是 fetch 超時 須要作額外處理;爲此,特地查詢了 fetch 相關的資料,整理了下;javascript

瀏覽器發起 http 請求,有兩種方式,XMLHttpRequest(xhr) 和 fetch;其中 xhr 是咱們常常使用的方式,fetch 是在 ES6 引入的,fetch 返回有一個 Promise 對象,寫法更加簡便友好;html

在個人項目中,我使用的是isomorphic-fetch。如今我對於這個包的理解,能夠 cross-runtime,也就是區分環境 node 仍是 瀏覽器;前端

  • node 環境使用 node-fetch
  • 舊瀏覽器使用 whatwg-fetch
  • 現代瀏覽器使用自身 fetch

fetch 用法

fetch 用法,MDN 中,講得比較清楚,在這裏這裏java

// fetch 返回Response的信息
{
  body: ReadableStream;
  bodyUsed: false;
  headers: Headers;
  ok: true;
  redirected: false;
  status: 200;
  statusText: "OK";
  type: "cors";
  url: "http://some-website.com/some-url";
  __proto__: Response;
}

請求的資源都存儲在 body 中,做爲一種可讀的流。因此須要調用一個恰當方法將可讀流轉換爲咱們可使用的數據。node

通常使用 response.json();若是是 xml 格式的,使用 response.text();若是是圖片資源,使用 response.blob();react

fetch 經常使用 API

- method: GET, POST, PUT, DELETE, HEAD。
- url: url地址。
- headers: 請求頭相關參數。
- referrer : no-referrer, client或者一個網址。默認爲client。
- mode: cors, no-cors, same-origin, navigate。默認爲cors。Chrome(v47~)目前的默認值是 same-origin。
- credentials: omit, same-origin, include。默認值omit。Chrome(v47~)目前的默認值是 include。
- redirect: follow, error, manual。Chrome(v47~)目前的默認值是 manual。
- integrity: Subresource Integrity(子資源完整性, SRI)的值
- cache: default, no-store, reload, no-cache, 或者 force-cache
- body: 要加到要求中的內容。注意,method爲GET或者HEAD時不使用這個值。

fetch 常見問題

fetch 請求默認不帶 cookie

前端請求的時候都會設計到 token 權限驗證,不少時候是存在 cookie 裏面的.fetch 裏面又一個參數 credentials 設計 cookie
credentials 有三個值:git

  • omit: 默認值,忽略 cookie 的發送
  • same-origin: 表示 cookie 只能同域發送,不能跨域發送
  • include: cookie 既能夠同域發送,也能夠跨域發送 ( 推薦使用)
    推薦使用 include.

fetch 跨域問題

fetch 跨域也有對應的參數設置 modees6

  • same-origin:該模式是不容許跨域的,它須要遵照同源策略,不然瀏覽器會返回一個 error 告知不能跨域;其對應的 response type 爲 basic。
  • cors: 該模式支持跨域請求,顧名思義它是以 CORS 的形式跨域;固然該模式也能夠同域請求不須要後端額外的 CORS 支持;其對應的 response type 爲 cors。
  • no-cors: 該模式用於跨域請求可是服務器不帶 CORS 響應頭,也就是服務端不支持 CORS;這也是 fetch 的特殊跨域請求方式;其對應的 response type 爲 opaque。

fetch 返回 400 500 問題

fetch 返回問題描述
當一個請求發送完成,服務返回狀態碼,fetch 不會 reject 這個 response,仍然 resolve,可是 response.ok 會設置成 false.不少時候咱們會二次封裝 fetch reject error.github

處理 404 500web

fetch 沒法 abort 請求 和 timeout

目前 fetch 沒有傳統 ajax 的 abort 方法,還在草案之中

Promise.race 解決方案

timeout 解決方案
使用 promise 的 race, 由於 promise 裏面的 resolve 和 reject 只能執行一次, 利用 race reject 一個 error.
上面的 abort 並無真正的 abort 這次請求,只是經過 promise promise reject 一個 error 而已.我在翻閱 fetch 的源碼的時候發現了這個

var p = Promise.race([
  fetch("/resource-that-may-take-a-while"),
  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error("request timeout")), 5000);
  }),
]);
p.then((response) => console.log(response));
p.catch((error) => console.log(error));

AbortController 解決方案

原生 fetch 方法 可使用 AbortController 來中斷;fetch 源碼,支持使用 signal 來進行中斷;

// fetch 源碼
if (request.signal && request.signal.aborted) {
  return reject(new DOMException("Aborted", "AbortError"));
}

具體代碼以下:

// 1 秒後停止
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);

try {
  let response = await fetch("/article/fetch-abort/demo/hang", {
    signal: controller.signal,
  });
} catch (err) {
  if (err.name == "AbortError") {
    // handle abort()
    alert("Aborted!");
  } else {
    throw err;
  }
}

Promise.race 和 AbortController 結合方案

具體看 這裏

代碼

fetch 封裝,對於 json text 圖片格式處理,以及 timeout、相關報錯等做了處理,能夠點擊獲取

綜述

總體文章,可能會有些問題,若有疑問,歡迎留言或者微信交流,共同窗習進步!

wechat img

參考文檔

fetch-MDN
fetch-源碼
Fetch:停止(Abort)
Isomorphic-Fetch 的詭異部份
fetch 詳解
對 fetch timeout 的思考
fetch 使用的常見問題及解決辦法
AJAX 與 Fetch API

相關文章
相關標籤/搜索