1. 程式人生 > >fetch API 簡單解讀

fetch API 簡單解讀

http://f2e.souche.com/blog/fetch-api-jie-du/?utm_source=tuicool&utm_medium=referral

在我們日常的前端開發中,XMLHttpRequest 是必不可少會遇到的一個東東。XHR 最初是由微軟引入其 MSXML的,Web 開發者需要通過 ActiveX 去呼叫,而後,Mozilla 開發者開發了一個近似的東西,為了方便在 JavaScript 中使用,才用 XMLHttpRequest 為名的物件封裝了一下。使用 XHR 發起一個請求,大致程式碼就會如下所示:

// 首先,需要些一些特徵檢測來做下瀏覽器相容
if (window.XMLHttpRequest) {  
  request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
  try {
    request = new ActiveXObject('Msxml2.XMLHTTP');
  } 
  catch (e) {
    try {
      request = new ActiveXObject('Microsoft.XMLHTTP');
    } 
    catch (e) {}
  }
}

// 然後開啟一個請求
request.open('GET', 'https://nodejs.org/api/http.json', true);  
// 真正意義上的請求
request.send(null);  
request.addEventListener('load', function() {  
    // 處理返回結果
})

以上的程式碼,相信每個前端開發都有寫過,然而就算不寫那一段長長的相容程式碼,光是後面發起請求的那段程式碼,也會讓人覺得頭大。就更不用說所謂的 XMLHttpRequest,其實現在幾乎沒人用 XML 做瀏覽器短的資料互動形式了。

儘管眾多三方框架已經封裝了一些好用的 api,例如 jQuery.ajax(),angular.js 的 $http,但是如果有個更簡單的方法呢?

Syntax

fetch() 的語法很簡單,如下所示:

fetch(input, init).then(function(response) { ... });  

其中:

input 引數,即可以直接傳入一個 url,也可以傳入一個 

Request 物件;

init 引數是可選,是一個包含了請求方法,請求頭部,請求主體,模式,憑證,快取模式等配置的物件。

從語法中可以看到,fetch() API 會返回一個 Promise

因此,開頭所提到的例子,可以修改成這樣:

fetch('https://nodejs.org/api/http.json').then(function(response) {  
    return // 響應處理
}).catch(function(err) {
    // 捕獲錯誤
});

除了普通的 get 請求,發起一個表單 POST 請求也是相當簡單:

fetch('/post/some/data', {  
    method: 'post',
    body: new FormData(document.querySelector('#form'))
});

同理,如果是 json 格式的資料的話:

fetch('/post/some/data', {  
    method: 'post',
    body: JSON.stringify({ user: 'lisposter', pwd: 'souche.com'})
});

響應處理

與上述 Request 對應的,Fetch API 還對應有一個 Response 用於表示響應結果,Response,是一個 Stream 物件,其提供了眾多便利的屬性及方法以供開發者處理。方法一般會返回一個 Promise,舉個例子,處理 json 資料。簡單示例:

fetch('https://nodejs.org/api/http.json')  
    .then(function(response) {
        return response.json();
    })
    .then(function(json) {
        // 此處的 json 已經被處理為 json 物件
    })
    .catch(function(err) {
        // 捕獲錯誤
    });

這裡,你當然也可以選擇使用傳統的 JSON.parse(),但無疑,使用 .json() 方法更加方便快捷,適合在 Promise 中使用。

同理,如果你希望處理請求結果為純文字,那麼 Response.text() 將會很有幫助。除此之外,還有 .blob()formData() 等方法可供使用。Fetch API 所支援的響應型別有如下幾種:

從 Response 的屬性中,我們也能輕易提取到響應頭部及 Metadata 的相關資訊:

fetch('https://nodejs.org/api/http.json').then(function(response) {  
    console.log(response.status);
    console.log(response.statusText);
    console.log(response.url);
    console.log(response.type);
    console.log(response.headers);

// 獲取頭部資訊需要使用 .get() 
console.log(response.headers.get('Content-Type'));  
})

其中,response.headers 就是一個 Header 型別的物件,我們可以使用 Headers 類提供的各種方法來操作,除了上面程式碼中的 .get() 方法外,Headers 還有 .has() 方法,用於檢查是否包含某個頭部資訊;.getAll() 方法,將制定的頭部資訊以陣列形式全部返回,等等,具體可以參考 Headers 型別文件

響應型別

每當我們用 fetch 發起一個請求,其響應都會被賦予一個響應型別,'basic','cors' 或者 'opaque'。

如果請求是同源的,那麼響應型別就是 'basic',如果跨域的請求,則是 'cors',如果對非同源的資源發起一個請求,並且其沒有返回 CORS 頭的話,則是 'opaque' 型別。'opaque' 型別的響應我們將不能讀取所返回的資料或者檢視請求的狀態,也就是說,我們壓根沒辦法知道請求是否成功了。

我們可以在發起請求的時候,指定一個模式來確保只有相應的請求會被允許:

  • same-origin: 只有同源的請求才會被允許。
  • cors: 允許同源或者非同源但是返回正確 CORS 頭部的請求。
  • cors-with-forced-preflight: 在正式請求之前,總是先發起一個 preflight 檢查。
  • no-cors: 用以發起非同源又沒有返回 CORS 頭的請求。

注意:因為 Cache API 還沒有在 window 物件中實現,因此,目前 fetch api 並沒有支援從 window 域中發起 no-cors 請求,但是你可以在 Service Worker 中使用。

投入使用

Fetch API 並沒有完全完成,因此,瀏覽器對其支援也不完全,在實際使用的時候還需要注意相容問題,可以通過特性檢查,檢查 Headers, Request, Response 或者 fetch 是否存在來判斷瀏覽器的支援情況。也可以參考 Can I Use 提供的相容情況列表。你也可以使用 GitHub 提供的 polyfill,他可以相容到最低 IE9,相信可以滿足大多數的情況了。

在未來,Cache API 的實現完成後,Fetch API 將能很好地處理離線狀態下的請求,這應該是大家最期待的特性了。