Fetch 入門

CC-Cai發表於2018-12-16

一、什麼是Fetch ?

Fetch的定義

Fetch本質上是一種標準,該標準定義了請求、響應和繫結的流程。 Fetch標準還定義了Fetch () JavaScript API,它在相當低的抽象級別上公開了大部分網路功能,我們今天講的主要是Fetch API。Fetch API 提供了一個獲取資源的介面(包括跨域)。它類似於 XMLHttpRequest ,但新的API提供了更強大和靈活的功能集。 Fetch 的核心在於對 HTTP 介面的抽象,包括 Request,Response,Headers,Body,以及用於初始化非同步請求的 global fetch。

二、如何使用Fetch

fetch() 方法的使用

Fetch API 提供了一種全域性fetch()方法,該方法位於 WorkerOrGlobalScope 這一個 mixin 中 方法用於發起獲取資源的請求。它返回一個 promise,這個 promise 會在請求響應後被 resolve,並傳回 Response 物件。

fetch(input?: Request | string, init?: RequestInit): Promise<Response>

fetch(url, options).then(function(response) {
  // 處理 HTTP 響應
}, function(error) {
  // 處理網路錯誤
})
複製程式碼

fetch() 引數

fetch方法可以接收兩個引數input和options。

  • input 引數可以是字串,包含要獲取資源的 URL。也可以是一個 Request 物件。

  • options 是一個可選引數。一個配置項物件,包括所有對請求的設定。可選的引數有:

method: 請求使用的方法,如 GET、POST。
headers: 請求的頭資訊,包含與請求關聯的Headers物件。
body: 請求的 body 資訊。注意 GET 或 HEAD 方法的請求不能包含 body 資訊
mode: 請求的模式,如 cors、 no-cors 或者 same-origin。
credentials: 請求的 credentials,如 omit、same-origin 或者 include。為了在當前域名內自動傳送 cookie , 必須提供這個選項。

常用的fetch請求

HTML

fetch('/index/fetchHtml')
  .then((res) => {
    return res.text()
  }).then((result) => {
    document.body.innerHTML += result
  })
  .catch((err) => {
  })
複製程式碼

JSON

fetch('/api/user/CaiCai')
  .then((res) => {
    return res.json()
  })
  .then((json) => {
    console.log(json)
  })
  .catch((err => {
  }))

複製程式碼

POST Form

function postForm() {
  const form = document.querySelector('form')
  const name = encodeURI(document.getElementsByName('name')[0].value)
  fetch(`/api/user/${name}`, {
    method: 'POST',
    body: new FormData(form)
  })
}
複製程式碼

POST JSON

fetch('/api/user/CaiCai', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'CaiCai',
    age: '26',
  })
})

複製程式碼

fetch注意事項

1. 錯誤處理

fetch只有在網路錯誤的情況,返回的promise會被reject。成功的 fetch() 檢查不僅要包括 promise 被 resolve,還要包括 Response.ok 屬性為 true。HTTP 404 狀態並不被認為是網路錯誤,所以Promise的狀態為resolve。

2. credentials 設定

fetch可以通過credentials自己控制傳送請求時是否帶上cookie。credentials可設定為include、same-origin、omit。include為了讓瀏覽器傳送包含憑據的請求(即使是跨域源)。如果你只想在請求URL與呼叫指令碼位於同一起源處時傳送憑據,請新增credentials: 'same-origin'。要改為確保瀏覽器不在請求中包含憑據,請使用credentials: 'omit'。

credentials 預設是“same-origin”,但是以下版本的瀏覽器實現了一個更老版本的fetch規範,其中預設是“忽略”: Firefox 39-60 Chrome 42 - 67 Safari 10.1 11.1.2 如果您的目標是這些瀏覽器,建議始終對所有fetch請求顯式指定憑據:'同源',而不是依賴於預設

3. 中止

fetch 自身並沒有提供 中止請求的方法。但是部分瀏覽器有實現AbortController,可以通過AbortController中止fetch請求

const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 5000);


fetch('/api/user/CaiCai', {
  signal, // 在option中加入signal
  method: 'POST',
  // credentials:'include',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'CaiCai',
    age: '26',
  })
}).then((res) => {
  return res.json()
}).then((result) => {
  console.log(result)
}).catch((err) => {
  console.log(err)
})

複製程式碼

4.相容性

以下Can I Use上顯示的,是fetch的相容性情況,目前已經支援大部分瀏覽器,不支援的瀏覽器可以使用fetch polyfill

Fetch 入門

三、為什麼要用Fetch、而不用XHR

1、fetch返回的是promise物件,比XMLHttpRequest的實現更簡潔,fetch 使用起來更簡潔 ,完成工作所需的實際程式碼量也更少
2、fetch 可自定義是否攜帶Cookie
3、fetch在ServiceWorker中使用,至於ServiceWorker能有什麼優勢,會在未來寫ServiceWorker的時候回寫到

四、為什麼放棄fetch

首先,謝謝各位同學的指出文章的中問題,標題確實欠妥,文不對題。這裡補充下fetch的一些問題:
1.fetch不支援jsonp,如果專案中使用到JSONP,需要單獨實現一個JSONP。
2.fetch自身並沒有提供abort的方法,需要AbortController去處理中止,實現起來會繁瑣一點。並且AbortController相容性不是很好,不過@周公來同學指出,我們可以使用“abortcontroller-polyfill”。
3.在我們平常使用中,fetch相對XHR差別不大,並且就像@jokerapi同學說的“實際業務上,api 請求都是用再次封裝好的函式來處理的。底層是 Fetch 還是 XHR 影響不大。”。所以如果沒有特別的需求,從XHR升級到fetch的意義不大。但是在ServiceWorker中fetch會大放異彩。目前淘寶首頁就使用fetch+ServiceWorker來實現離線快取。

Fetch 入門

參考連結:

Fetch API
開始學習Fetch
淺談 Fetch
fetch polyfill