Fetch 常見的使用問題


▶fetch的瀏覽器兼容


 

㈠fetch默認不攜帶cookie

⑴fetch發送請求默認是不發送cookie的,不管是同域還是跨域;

  需要設置 :

fetch(url, {credentials: 'include'})

 

可以配置其credentials項,其有3個值:

omit: 默認值,忽略cookie的發送

same-origin: 表示cookie只能同域發送,不能跨域發送

include: cookie既可以同域發送,也可以跨域發送

 

⑵fetch默認對服務端通過Set-Cookie頭設置的cookie也會忽略,若想選擇接受來自服務端的cookie信息,也必須要配置credentials選項

 

㈡fetch請求對某些錯誤http狀態不會reject

⑴這主要是由fetch返回promise導致的,因為fetch返回的promise在某些錯誤的http狀態下如400、500不會reject,相反它會被resolve

⑵只有網絡錯誤會導致請求不能完成時,fetch 才會被 reject;所以一般會對fetch請求做一層封裝

 

⑶示例:

function checkStatus(response) {   if (response.status >= 200 && response.status < 300) {     return response;   }   const error = new Error(response.statusText);   error.response = response;   throw error; } function parseJSON(response) {   return response.json(); } export default function request(url, options) {   let opt = options||{};   return fetch(url, {credentials: 'include', ...opt})     .then(checkStatus)     .then(parseJSON)     .then((data) => ( data ))      .catch((err) => ( err ));

 

㈢fetch不支持超時timeout處理

⑴fetch不像大多數ajax庫那樣對請求設置超時timeout,它沒有有關請求超時的feature,所以在fetch標准添加超時feature之前,都需要polyfill該特性。

⑵實際上,我們真正需要的是abort(), timeout可以通過timeout+abort方式來實現,起到真正超時丟棄當前的請求。

⑶而在目前的fetch指導規范中,fetch並不是一個具體實例,而只是一個方法

⑷其返回的promise實例根據Promise指導規范標准是不能abort的,也不能手動改變promise實例的狀態,只能由內部來根據請求結果改變promise的狀態

⑸因此:

實現fetch的timeout功能,其思想就是新創建一個可以手動控制promise狀態的實例

根據不同情況來對新promise實例進行resolve或者reject,從而達到實現timeout的功能;

 

⑹目前可以有兩種不同的解決方法:

第一種:單純setTimeout方式

var oldFetchfn = fetch; //攔截原始的fetch方法  window.fetch = function(input, opts){//定義新的fetch方法,封裝原有的fetch方法 return new Promise(function(resolve, reject){ var timeoutId = setTimeout(function(){ reject(new Error("fetch timeout")) }, opts.timeout); oldFetchfn(input, opts).then( res=>{ clearTimeout(timeoutId); resolve(res) }, err=>{ clearTimeout(timeoutId); reject(err) } ) }) }

 

在上面基礎上可以模擬類似XHR的abort功能:

var oldFetchfn = fetch; window.fetch = function(input, opts){ return new Promise(function(resolve, reject){ var abort_promise = function(){ reject(new Error("fetch abort")) }; var p = oldFetchfn(input, opts).then(resolve, reject); p.abort = abort_promise; return p; }) }

 

②第二種方法:利用Promise.race方法

Promise.race方法接受一個promise實例數組參數,表示多個promise實例中任何一個最先改變狀態,那么race方法返回的promise實例狀態就跟着改變。

var oldFetchfn = fetch; //攔截原始的fetch方法  window.fetch = function(input, opts){//定義新的fetch方法,封裝原有的fetch方法 var fetchPromise = oldFetchfn(input, opts); var timeoutPromise = new Promise(function(resolve, reject){ setTimeout(()=>{ reject(new Error("fetch timeout")) }, opts.timeout) }); retrun Promise.race([fetchPromise, timeoutPromise]) }

 

⑺timeout不是請求連接超時的含義,它表示請求的response時間,包括請求的連接、服務器處理及服務器響應回來的時間

 

⑻fetch的timeout即使超時發生了,本次請求也不會被abort丟棄掉,它在后台仍然會發送到服務器端只是本次請求的響應內容被丟棄而已

 

㈣fetch不支持JSONP

⑴fetch是與服務器端進行異步交互的,而JSONP是外鏈一個javascript資源,並不是真正ajax,所以fetch與JSONP沒有什么直接關聯,當然至少目前是不支持JSONP的。

⑵我們要實現一個JSONP,只不過這個JSONP的實現要與fetch的實現類似,即基於Promise來實現一個JSONP;而其外在表現給人感覺是fetch支持JSONP一樣;

 

⑶JSONP的實現步驟如下:

①首先需要用npm安裝fetch-jsonp

npm install fetch-jsonp --save-dev

 

②然后在像下面一樣使用:

fetchJsonp('/users.jsonp', { timeout: 3000, jsonpCallback: 'custom_callback' }) .then(function(response) { return response.json() }).catch(function(ex) { console.log('parsing failed', ex) })

 

㈤fetch不支持progress事件

XHR是原生支持progress事件的

⑵但是呢,根據fetch的指導規范標准,其內部設計實現了RequestResponse類;

   其中Response封裝一些方法和屬性,通過Response實例可以訪問這些方法和屬性:

⑶例如response.json()response.body等等;

⑷response.body是一個可讀字節流對象,其實現了一個getRender()方法,其具體作用是:

getRender()方法用於讀取響應的原始字節流,該字節流是可以循環讀取的,直至body內容傳輸完成

 

㈥fetch跨域問題

⑴XHR2是支持跨域請求的,只不過要滿足瀏覽器端支持CORS,服務器通過Access-Control-Allow-Origin來允許指定的源進行跨域,僅此一種方式。

⑵fetch也是支持跨域請求的,只不過其跨域請求做法與XHR2一樣,需要客戶端與服務端支持

⑶fetch還支持一種跨域,不需要服務器支持的形式,具體可以通過其mode的配置項來說明。

⑷fetch的mode配置項有3個值:

same-origin該模式是不允許跨域的,它需要遵守同源策略,否則瀏覽器會返回一個error告知不能跨域;其對應的response type為basic

 

cors: 該模式支持跨域請求,顧名思義它是以CORS的形式跨域;當然該模式也可以同域請求不需要后端額外的CORS支持;其對應的response type為cors

 

no-cors: 該模式用於跨域請求但是服務器不帶CORS響應頭,也就是服務端不支持CORS;這也是fetch的特殊跨域請求方式;其對應的response type為opaque

 

⑸針對跨域請求,cors模式是常見跨域請求實現,但是fetch自帶的no-cors跨域請求模式則較為陌生,該模式有一個比較明顯的特點:

該模式允許瀏覽器發送本次跨域請求,但是不能訪問響應返回的內容,這也是其response type為opaque透明的原因。

⑹這與<img/>發送的請求類似,只是該模式不能訪問響應的內容信息;但是它可以被其他APIs進行處理,例如ServiceWorker。

⑺另外,該模式返回的repsonse可以在Cache API中被存儲起來以便后續的對它的使用,這點對script、css和圖片的CDN資源是非常合適的,

   因為這些資源響應頭中都沒有CORS頭

 

總的來說,fetch的跨域請求是使用CORS方式,需要瀏覽器和服務端的支持。

㈦不可以取消

1.fetch不支持abort,不支持超時控制,使用setTimeout及Promise.reject的實現的超時控制並不能阻止請求過程繼續在后台運行,造成了流量的浪費。

2.fetch沒有辦法原生監測請求的進度,而XHR可以

 

參考:https://www.cnblogs.com/huilixieqi/p/6494380.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM