使用Fetch

2018-01-23 10:11 更新

Fetch API提供了一個 JavaScript 接口用于訪問和操作HTTP管道的零件,如請求和響應。它還提供了一種全局fetch()方法,可以提供一種簡單,合理的方式在網絡上異步獲取資源。

此類功能以前是使用 XMLHttpRequest 實現(xiàn)的。Fetch提供了一個更好的替代方法,可以很容易地被其他技術使用,如Service Workers。Fetch還提供了一個單一的邏輯位置來定義其他HTTP相關的概念,如CORS和HTTP的擴展。

請注意,F(xiàn)etch規(guī)格不同于jQuery.ajax(),主要體現(xiàn)在兩個方面:

  • 即使響應是HTTP 404或500,從 fetch() 返回的Promise也不會拒絕HTTP錯誤狀態(tài)。相反,它將正常解析(ok狀態(tài)設置為false),并且它只會在網絡故障時拒絕,或者如果任何東西阻止了請求的完成
  • 默認情況下, 如果站點依靠維護用戶會話(發(fā)送cookie,必須設置credentials init選項),則fetch不會發(fā)送或接收來自服務器的任何cookie,從而導致未經身份驗證的請求。

Fetch請求

基本的Fetch請求非常容易設置??纯聪旅娴拇a:

var myImage = document.querySelector('img');

fetch('flowers.jpg').then(function(response) {
  return response.blob();
}).then(function(myBlob) {
  var objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

在這里,我們通過網絡獲取圖像并將其插入到一個<img>元素中。最簡單的用法是fetch()帶一個參數(shù) - 要獲取的資源的路徑 - 并返回一個包含響應(Response對象)的promise。

這當然只是一個HTTP響應,而不是實際的圖像。為了從響應中提取圖像主體內容,我們使用blob()方法(在Body mixin混合中定義,由Request對象和Response對象實現(xiàn))。

注意:Body mixin也有類似的方法來提取其他類型的Body內容;請參閱正文部分了解更多信息。

一個objectURL接著從所提取的Blob創(chuàng)建,然后將其插入img。

獲取請求由內容安全策略connect-src指令控制,而不是由它檢索的資源指令控制。

提供請求選項

該fetch()方法可以選擇性地接受第二個參數(shù),一個 init 對象,允許你控制許多不同的設置:

有關可用選項的詳細說明,請參閱fetch()。

var myHeaders = new Headers();

var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };

fetch('flowers.jpg', myInit).then(function(response) {
  return response.blob();
}).then(function(myBlob) {
  var objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

發(fā)送包含憑據(jù)的請求

要使瀏覽器發(fā)送包含憑據(jù)的請求,即使是跨源調用,請向傳遞給fetch()方法的init對象添加credentials: 'include':

fetch('https://example.com', {
  credentials: 'include'  
})

如果您只想在請求URL與調用腳本位于相同的源時發(fā)送憑據(jù),請?zhí)砑?nbsp; credentials: 'same-origin'。

// The calling script is on the origin 'https://example.com'

fetch('https://example.com', {
  credentials: 'same-origin'  
})

要改為確保瀏覽器不在請求中包含憑據(jù),請使用credentials: 'omit'。

fetch('https://example.com', {
  credentials: 'omit'  
})

上傳JSON數(shù)據(jù)

使用fetch()開機自檢JSON編碼的數(shù)據(jù)。

var url = 'https://example.com/profile';
var data = {username: 'example'};

fetch(url, {
  method: 'POST', // or 'PUT'
  body: JSON.stringify(data), 
  headers: new Headers({
    'Content-Type': 'application/json'
  })
}).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));

上傳文件

可以使用 HTML <input type="file"/> input 元素、FormData () 和fetch()來上載文件。

var formData = new FormData();
var fileField = document.querySelector("input[type='file']");

formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);

fetch('https://example.com/profile/avatar', {
  method: 'PUT',
  body: formData
})
.then(response => response.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));

檢查fetch是否成功

當遇到網絡錯誤或服務器端的 CORS 配置不正確時,一個fetch()承諾將拒絕TypeError,盡管這通常意味著權限問題或類似的情況 - 例如,404不構成一個網絡錯誤。一個成功的fetch()的準確檢查將包括檢查承諾解決,然后檢查該Response.ok屬性的值為true。代碼看起來像這樣:

fetch('flowers.jpg').then(function(response) {
  if(response.ok) {
    return response.blob();
  }
  throw new Error('Network response was not ok.');
}).then(function(myBlob) { 
  var objectURL = URL.createObjectURL(myBlob); 
  myImage.src = objectURL; 
}).catch(function(error) {
  console.log('There has been a problem with your fetch operation: ', error.message);
});

提供您自己的請求對象

您可以使用Request()構造函數(shù)創(chuàng)建請求對象,并將其作為fetch()方法參數(shù)傳入,而不是將要請求的資源的路徑傳遞到 fetch () 調用中。

var myHeaders = new Headers();

var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };

var myRequest = new Request('flowers.jpg', myInit);

fetch(myRequest).then(function(response) {
  return response.blob();
}).then(function(myBlob) {
  var objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

Request()接受與該fetch()方法完全相同的參數(shù)。您甚至可以傳入現(xiàn)有的請求對象來創(chuàng)建它的副本:

var anotherRequest = new Request(myRequest, myInit);

這非常有用,因為請求和響應主體只是一個用途。制作這樣的副本可以讓您再次使用請求/響應,同時根據(jù)需要改變init選項。復制必須在閱讀正文之前完成,并且閱讀正文中的正文也將其標記為原始請求中的正文。

注意:還有一種clone()方法可以創(chuàng)建副本。如果原始請求或響應的主體已經被讀取,則創(chuàng)建副本的兩種方法都將失敗,但是讀取克隆的響應或請求的主體不會導致它在原始中被標記為已讀。

Headers

該Headers接口允許您通過Headers()構造函數(shù)創(chuàng)建自己的headers對象。headers對象是名稱到值的簡單多重映射:

var content = "Hello World";
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");

同樣可以通過傳遞一個數(shù)組或一個對象字面值給構造函數(shù)來實現(xiàn):

myHeaders = new Headers({
  "Content-Type": "text/plain",
  "Content-Length": content.length.toString(),
  "X-Custom-Header": "ProcessThisImmediately",
});

內容可以被查詢和檢索:

console.log(myHeaders.has("Content-Type")); // true
console.log(myHeaders.has("Set-Cookie")); // false
myHeaders.set("Content-Type", "text/html");
myHeaders.append("X-Custom-Header", "AnotherValue");
 
console.log(myHeaders.get("Content-Length")); // 11
console.log(myHeaders.get("X-Custom-Header")); // ["ProcessThisImmediately", "AnotherValue"]
 
myHeaders.delete("X-Custom-Header");
console.log(myHeaders.get("X-Custom-Header")); // [ ]

其中的一些操作只是在 ServiceWorkers 中很有用,但是它們提供了一個更好的API來處理headers。

如果使用的headers名不是有效的HTTP Header名稱稱,則所有的Headers方法都會拋出一個TypeError。如果有一個不變的guar,變異操作將會拋出一個TypeError(見下文)。否則,他們默默地失敗。例如:

var myResponse = Response.error();
try {
  myResponse.headers.set("Origin", "http://mybank.com");
} catch(e) {
  console.log("Cannot pretend to be a bank!");
}

headers的一個很好的用例是在進一步處理之前檢查內容類型是否正確。例如:

fetch(myRequest).then(function(response) {
    var contentType = response.headers.get("content-type");
    if(contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
  })
  .then(function(json) { /* process your JSON further */ })
  .catch(function(error) { console.log(error); });

Guard

由于headers可以在請求中發(fā)送,并在響應中收到,并且對于哪些信息可以并且應該是可變的有各種限制,headers對象具有guard屬性。這不會暴露給Web,但會影響headers對象上允許使用的變異操作。

可能的guard值是:

  • none:默認。
  • request:從請求(Request.headers)中獲得的headers對象的guard。
  • request-no-cors:從使用創(chuàng)建的請求獲取headers對象的guard。Request.mode no-cors
  • response:從響應(Response.headers)獲得的headers的guard。
  • immutable:主要用于ServiceWorkers;呈現(xiàn)只讀headers對象。

注意:您不能追加或設置request保護的Headers的 Content-Length headers。同樣,Set-Cookie不允許插入響應頭:ServiceWorkers不允許通過合成響應來設置cookie。

Response對象

正如你上面看到的,當fetch() promise被解析時,Response實例被返回。

您將使用的最常見的響應屬性是:

  • Response.status - 包含響應狀態(tài)碼的整數(shù)(默認值200)。
  • Response.statusText - 一個字符串(默認值“OK”),對應于HTTP狀態(tài)碼消息。
  • Response.ok - 在使用上面看,這是一個用于檢查狀態(tài)是否在200-299范圍內的簡寫。這返回一個Boolean。

它們也可以通過JavaScript以編程方式創(chuàng)建,但在ServiceWorkers中,當您使用respondWith()方法提供對接收到的請求的自定義響應時,這只會非常有用:

var myBody = new Blob();

addEventListener('fetch', function(event) { // ServiceWorker intercepting a fetch
  event.respondWith(
    new Response(myBody, {
      headers: { "Content-Type" : "text/plain" }
    })
  );
});

所述Response()構造函數(shù)有兩個可選的參數(shù)- 一個用于響應的主體,和一個初始化對象(類似于接受的Request())

    注意:靜態(tài)方法error()只是返回錯誤響應。同樣,redirect()返回一個響應導致重定向到指定的URL。這些也只與Service Workers有關。

    Body

    請求和響應都可能包含body數(shù)據(jù)。一個body是以下任何一種類型的實例:

    • ArrayBuffer
    • ArrayBufferView (Uint8Array和擴展)
    • Blob/File
    • string
    • URLSearchParams
    • FormData

    Body mixin定義了以下方法來提取體(由得到的Request和Response實施)。這些都會返回一個最終解決實際內容的承諾。

    • arrayBuffer()
    • blob()
    • json()
    • text()
    • formData()

    這使得使用非文本數(shù)據(jù)比使用XHR更容易。

    請求體可以通過傳遞身體參數(shù)來設置:

    var form = new FormData(document.getElementById('login-form'));
    fetch("/login", {
      method: "POST",
      body: form
    });

    請求和響應(以及擴展fetch()功能)都將嘗試智能地確定內容類型。請求會自動設置Content-Type header,如果字典中沒有設置。

    Feature檢測

    通過檢查Window或Worker范圍中的Headers,Request,Response或fetch()是否存在,可以檢測到Fetch API支持。例如:

    if (self.fetch) {
        // run my fetch request here
    } else {
        // do something with XMLHttpRequest?
    }

    Polyfill

    要在不受支持的瀏覽器中使用Fetch,可以使用Fetch Polyfill,為不支持的瀏覽器重新創(chuàng)建功能。

    規(guī)范

    規(guī)范狀態(tài)評論
    Fetch
    Living Standard
    Initial definition

    瀏覽器兼容性

    • 電腦端
    Feature
    Chrome
    Edge
    Firefox(Gecko)Internet Explorer
    Opera
    Safari(WebKit)
    基本的支持支持:42支持:14
    支持:
    39(39)
    34(34)[1] 
    52(52)[2]
    不支持支持:29、28 [1]支持:10.1
    • 移動端
    FeatureAndroid WebviewChrome for AndroidFirefox Mobile (Gecko)IE PhoneOpera MobileSafari Mobile
    基本的支持
    支持:42支持:42支持不支持?支持:10.1

    對應的角標解釋:

    [1]這個API是在首選項后面實現(xiàn)的。

    [2]在Firefox 52之前,get()只返回指定頭文件中的第一個值,getAll()返回所有的值。從52開始,get()現(xiàn)在返回所有值getAll()并被刪除。

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

    掃描二維碼

    下載編程獅App

    公眾號
    微信公眾號

    編程獅公眾號