国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

fetch使用的常見問題及其解決辦法

pubdreamcc / 1564人閱讀

首先聲明一下,本文不是要講解fetch的具體用法,不清楚的可以參考MDN fetch教程。

引言

說道fetch就不得不提XMLHttpRequest了,XHR在發(fā)送web請求時(shí)需要開發(fā)者配置相關(guān)請求信息和成功后的回調(diào),盡管開發(fā)者只關(guān)心請求成功后的業(yè)務(wù)處理,但是也要配置其他繁瑣內(nèi)容,導(dǎo)致配置和調(diào)用比較混亂,也不符合關(guān)注分離的原則;fetch的出現(xiàn)正是為了解決XHR存在的這些問題。例如下面代碼:

fetch(url).then(function(response) {
  return response.json();
}).then(function(data) {
  console.log(data);
}).catch(function(e) {
  console.log("Oops, error");
});

上面這段代碼讓開發(fā)者只關(guān)注請求成功后的業(yè)務(wù)邏輯處理,其他的不用關(guān)心,相當(dāng)簡單;也比較符合現(xiàn)代Promise形式,比較友好。

fetch是基于Promise設(shè)計(jì)的,從上面代碼也能看得出來,這就要求fetch要配合Promise一起使用。正是這種設(shè)計(jì),fetch所帶來的優(yōu)點(diǎn)正如傳統(tǒng) Ajax 已死,F(xiàn)etch 永生總結(jié)的一樣:

語法簡單,更加語義化

基于標(biāo)準(zhǔn)的Promise實(shí)現(xiàn),支持async/await

使用isomorphic-fetch可以方便同構(gòu)

不過話說回來,fetch雖然有很多優(yōu)點(diǎn),但是使用fetch來進(jìn)行項(xiàng)目開發(fā)時(shí),也是有一些常見問題的,下面就來說說fetch使用的常見問題。

fetch兼容性

fetch是相對較新的技術(shù),當(dāng)然就會存在瀏覽器兼容性的問題,借用上面應(yīng)用文章的一幅圖加以說明fetch在各種瀏覽器的原生支持情況:

從上圖可以看出,在各個(gè)瀏覽器低版本的情況下都是不被支持的。

那么問題來了,如何在所有瀏覽器中通用fetch呢,當(dāng)然就要考慮fetch的polyfill了。

上面說過,fetch是基于Promise來實(shí)現(xiàn)的,所以在低版本瀏覽器中Promise可能也未被原生支持,所以還需要Promise的polyfill;大多數(shù)情況下,實(shí)現(xiàn)fetch的polyfill需要涉及到的:

promise的polyfill,例如es6-promise、babel-polyfill提供的promise實(shí)現(xiàn)。

fetch的polyfill實(shí)現(xiàn),例如isomorphic-fetch和whatwg-fetch

這樣是否就可以安全的使用fetch來進(jìn)行前后端通信了?上面說了在大多數(shù)情況下是這樣,但是IE8/9則比較特殊:IE8它使用的是ES3,而IE9則對ES5部分支持。這種情況下還需要ES5的polyfill es5-shim支持了。

上述有關(guān)promise的polyfill實(shí)現(xiàn),需要說明的是:

babel-runtime是不能作為Promise的polyfill的實(shí)現(xiàn)的,否則在IE8/9下使用fetch會報(bào)Promise未定義。為什么?我想大家猜到了,因?yàn)閎abel-runtime實(shí)現(xiàn)的polyfill是局部實(shí)現(xiàn)而不是全局實(shí)現(xiàn),fetch底層實(shí)現(xiàn)用到Promise就是從全局中去取的,拿不到這報(bào)上述錯(cuò)誤。

另外,順便補(bǔ)充一下fetch的polyfill實(shí)現(xiàn)思路是:

首先判斷瀏覽器是否原生支持fetch,否則結(jié)合Promise使用XMLHttpRequest的方式來實(shí)現(xiàn);這正是whatwg-fetch的實(shí)現(xiàn)思路,而同構(gòu)應(yīng)用中使用的isomorphic-fetch,其客戶端fetch的實(shí)現(xiàn)是直接require whatwg-fetch來實(shí)現(xiàn)的。

fetch默認(rèn)不攜帶cookie

fetch發(fā)送請求默認(rèn)是不發(fā)送cookie的,不管是同域還是跨域;那么問題就來了,對于那些需要權(quán)限驗(yàn)證的請求就可能無法正常獲取數(shù)據(jù),這時(shí)可以配置其credentials項(xiàng),其有3個(gè)值:

omit: 默認(rèn)值,忽略cookie的發(fā)送

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

include: cookie既可以同域發(fā)送,也可以跨域發(fā)送

credentials所表達(dá)的含義,其實(shí)與XHR2中的withCredentials屬性類似,表示請求是否攜帶cookie;具體可以參考阮一峰老師的跨域資源共享 CORS 詳解中withCredentials一節(jié)的介紹;

這樣,若要fetch請求攜帶cookie信息,只需設(shè)置一下credentials選項(xiàng)即可,例如fetch(url, {credentials: "include"});

另外補(bǔ)充一點(diǎn):

fetch默認(rèn)對服務(wù)端通過Set-Cookie頭設(shè)置的cookie也會忽略,若想選擇接受來自服務(wù)端的cookie信息,也必須要配置credentials選項(xiàng);

fetch請求對某些錯(cuò)誤http狀態(tài)不會reject

這主要是由fetch返回promise導(dǎo)致的,因?yàn)閒etch返回的promise在某些錯(cuò)誤的http狀態(tài)下如400、500等不會reject,相反它會被resolve;只有網(wǎng)絡(luò)錯(cuò)誤會導(dǎo)致請求不能完成時(shí),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不支持超時(shí)timeout處理

用過fetch的都知道,fetch不像大多數(shù)ajax庫那樣對請求設(shè)置超時(shí)timeout,它沒有有關(guān)請求超時(shí)的feature,這一點(diǎn)比較蛋疼。所以在fetch標(biāo)準(zhǔn)添加超時(shí)feature之前,都需要polyfill該特性。

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

而在目前的fetch指導(dǎo)規(guī)范中,fetch并不是一個(gè)具體實(shí)例,而只是一個(gè)方法;其返回的promise實(shí)例根據(jù)Promise指導(dǎo)規(guī)范標(biāo)準(zhǔn)是不能abort的,也不能手動(dòng)改變promise實(shí)例的狀態(tài),只能由內(nèi)部來根據(jù)請求結(jié)果來改變promise的狀態(tài)。

既然不能手動(dòng)控制fetch方法執(zhí)行后返回的promise實(shí)例狀態(tài),那么是不是可以創(chuàng)建一個(gè)可以手動(dòng)控制狀態(tài)的新Promise實(shí)例呢。所以:

實(shí)現(xiàn)fetch的timeout功能,其思想就是新創(chuàng)建一個(gè)可以手動(dòng)控制promise狀態(tài)的實(shí)例,根據(jù)不同情況來對新promise實(shí)例進(jìn)行resolve或者reject,從而達(dá)到實(shí)現(xiàn)timeout的功能;

根據(jù)github上timeout handling上的討論,目前可以有兩種不同的解決方法:

方法一:單純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)
            }
        )
    })
}

當(dāng)然在上面基礎(chǔ)上可以模擬類似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方法接受一個(gè)promise實(shí)例數(shù)組參數(shù),表示多個(gè)promise實(shí)例中任何一個(gè)最先改變狀態(tài),那么race方法返回的promise實(shí)例狀態(tài)就跟著改變,具體可以參考這里。

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])
}

最后,對fetch的timeout的上述實(shí)現(xiàn)方式補(bǔ)充幾點(diǎn):

timeout不是請求連接超時(shí)的含義,它表示請求的response時(shí)間,包括請求的連接、服務(wù)器處理及服務(wù)器響應(yīng)回來的時(shí)間;

fetch的timeout即使超時(shí)發(fā)生了,本次請求也不會被abort丟棄掉,它在后臺仍然會發(fā)送到服務(wù)器端,只是本次請求的響應(yīng)內(nèi)容被丟棄而已;

fetch不支持JSONP

fetch是與服務(wù)器端進(jìn)行異步交互的,而JSONP是外鏈一個(gè)javascript資源,并不是真正ajax,所以fetch與JSONP沒有什么直接關(guān)聯(lián),當(dāng)然至少目前是不支持JSONP的。

這里我們把JSONP與fetch關(guān)聯(lián)在一起有點(diǎn)差強(qiáng)人意,fetch只是一個(gè)ajax庫,我們不可能使fetch支持JSONP;只是我們要實(shí)現(xiàn)一個(gè)JSONP,只不過這個(gè)JSONP的實(shí)現(xiàn)要與fetch的實(shí)現(xiàn)類似,即基于Promise來實(shí)現(xiàn)一個(gè)JSONP;而其外在表現(xiàn)給人感覺是fetch支持JSONP一樣;

目前比較成熟的開源JSONP實(shí)現(xiàn)fetch-jsonp給我們提供了解決方案,想了解可以自行前往。不過再次想嘮叨一下其JSONP的實(shí)現(xiàn)步驟,因?yàn)樵诒救嗣嬖嚨那岸撕蜻x人中大部分人對JSONP的實(shí)現(xiàn)語焉不詳;

使用它非常簡單,首先需要用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事件的,例如下面代碼這樣:

var xhr = new XMLHttpRequest()
xhr.open("POST", "/uploads")
xhr.onload = function() {}
xhr.onerror = function() {}
function updateProgress (event) {
  if (event.lengthComputable) {
    var percent = Math.round((event.loaded / event.total) * 100)
    console.log(percent)
  }
xhr.upload.onprogress =updateProgress; //上傳的progress事件
xhr.onprogress = updateProgress; //下載的progress事件
}
xhr.send();

但是fetch是不支持有關(guān)progress事件的;不過可喜的是,根據(jù)fetch的指導(dǎo)規(guī)范標(biāo)準(zhǔn),其內(nèi)部設(shè)計(jì)實(shí)現(xiàn)了RequestResponse類;其中Response封裝一些方法和屬性,通過Response實(shí)例可以訪問這些方法和屬性,例如response.json()response.body等等;

值得關(guān)注的地方是,response.body是一個(gè)可讀字節(jié)流對象,其實(shí)現(xiàn)了一個(gè)getRender()方法,其具體作用是:

getRender()方法用于讀取響應(yīng)的原始字節(jié)流,該字節(jié)流是可以循環(huán)讀取的,直至body內(nèi)容傳輸完成;

因此,利用到這點(diǎn)可以模擬出fetch的progress,具體可以參考這篇文章2016 - the year of web streams。

代碼實(shí)現(xiàn)如下,在線demo請參考fetch progress demo。

// fetch() returns a promise that resolves once headers have been received
fetch(url).then(response => {
  // response.body is a readable stream.
  // Calling getReader() gives us exclusive access to the stream"s content
  var reader = response.body.getReader();
  var bytesReceived = 0;

  // read() returns a promise that resolves when a value has been received
  reader.read().then(function processResult(result) {
    // Result objects contain two properties:
    // done  - true if the stream has already given you all its data.
    // value - some data. Always undefined when done is true.
    if (result.done) {
      console.log("Fetch complete");
      return;
    }

    // result.value for fetch streams is a Uint8Array
    bytesReceived += result.value.length;
    console.log("Received", bytesReceived, "bytes of data so far");

    // Read some more, and call this function again
    return reader.read().then(processResult);
  });
});

另外,github上也有使用Promise+XHR結(jié)合的方式實(shí)現(xiàn)類fetch的progress效果(當(dāng)然這跟fetch完全不搭邊)可以參考這里,具體代碼如下:

function fetchProgress(url, opts={}, onProgress){
    return new Promise(funciton(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.open(opts.method || "get", url);
        for(var key in opts.headers || {}){
            xhr.setRequestHeader(key, opts.headers[key]);
        }

        xhr.onload = e => resolve(e.target.responseText)
        xhr.onerror = reject;
        if (xhr.upload && onProgress){
            xhr.upload.onprogress = onProgress; //上傳
        }
        if ("onprogerss" in xhr && onProgress){
            xhr.onprogress = onProgress; //下載
        }
        xhr.send(opts.body)
    })
}
fetchProgress("/upload").then(console.log)
fetch跨域問題

既然是ajax庫,就不可避免與跨域扯上關(guān)系;XHR2是支持跨域請求的,只不過要滿足瀏覽器端支持CORS,服務(wù)器通過Access-Control-Allow-Origin來允許指定的源進(jìn)行跨域,僅此一種方式。

與XHR2一樣,fetch也是支持跨域請求的,只不過其跨域請求做法與XHR2一樣,需要客戶端與服務(wù)端支持;另外,fetch還支持一種跨域,不需要服務(wù)器支持的形式,具體可以通過其mode的配置項(xiàng)來說明。

fetch的mode配置項(xiàng)有3個(gè)值,如下:

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

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

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

針對跨域請求,cors模式是常見跨域請求實(shí)現(xiàn),但是fetch自帶的no-cors跨域請求模式則較為陌生,該模式有一個(gè)比較明顯的特點(diǎn):

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

這與發(fā)送的請求類似,只是該模式不能訪問響應(yīng)的內(nèi)容信息;但是它可以被其他APIs進(jìn)行處理,例如ServiceWorker。另外,該模式返回的repsonse可以在Cache API中被存儲起來以便后續(xù)的對它的使用,這點(diǎn)對script、css和圖片的CDN資源是非常合適的,因?yàn)檫@些資源響應(yīng)頭中都沒有CORS頭。

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

參考文獻(xiàn)

thats-so-fetch

傳統(tǒng) Ajax 已死,F(xiàn)etch 永生

Fetch進(jìn)階指南

2016 - the year of web streams

fetch API 簡介

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/81745.html

相關(guān)文章

  • fetch使用常見問題及其解決辦法

    摘要:首先聲明一下,本文不是要講解的具體用法,不清楚的可以參考教程。該模式用于跨域請求但是服務(wù)器不帶響應(yīng)頭,也就是服務(wù)端不支持這也是的特殊跨域請求方式其對應(yīng)的為。 首先聲明一下,本文不是要講解fetch的具體用法,不清楚的可以參考 MDN fetch教程。 fetch默認(rèn)不攜帶cookie 配置其 credentials 項(xiàng),其有3個(gè)值: omit: 默認(rèn)值,忽略cookie的發(fā)送 sam...

    pkwenda 評論0 收藏0
  • CoderPad-基于React全家桶寫作/新聞一體綜合應(yīng)用實(shí)踐總結(jié)

    摘要:基于全家桶寫作新聞一體綜合應(yīng)用的實(shí)踐總結(jié)在線地址大家伙兒們,又見面了。參照但不可否認(rèn)非常符合的思想,都在處理大規(guī)模數(shù)據(jù)時(shí)彰顯優(yōu)勢。最好的辦法是使用部署環(huán)境。細(xì)致的拆分,解耦性更好,以為單位進(jìn)行修改時(shí),大大降低誤傷率的同時(shí),隔離無關(guān)的信息。 ?CoderPad-基于React全家桶寫作/新聞一體綜合應(yīng)用的實(shí)踐總結(jié) showImg(https://segmentfault.com/img/...

    DC_er 評論0 收藏0
  • Spring Boot QuickStart (5) - Spring Data JPA

    摘要:關(guān)聯(lián)關(guān)系的關(guān)聯(lián)關(guān)系定義上,感覺并不是很靈活,姿勢也比較難找。如,定義在關(guān)聯(lián)關(guān)系上的參數(shù)可以設(shè)置級聯(lián)的相關(guān)東西。因?yàn)樾蛄谢瘯婕暗綄?shí)體類關(guān)聯(lián)對象的獲取,會觸發(fā)所有的關(guān)聯(lián)關(guān)系。 接(4) - Database 系列. Java Persistence API,可以理解就是 Java 一個(gè)持久化標(biāo)準(zhǔn)或規(guī)范,Spring Data JPA 是對它的實(shí)現(xiàn)。并且提供多個(gè) JPA 廠商適配,如 Hi...

    sutaking 評論0 收藏0
  • ant Design Pro區(qū)塊安裝npm run fetch:blocks問題解決

    摘要:原文今天折騰了一天終于把版本安裝完成了,問題最多的就是安裝區(qū)塊問題,官方文檔可以在項(xiàng)目跟目錄中執(zhí)行來下載所有的區(qū)塊。得到的界面將與中相同。此時(shí),打開下面發(fā)現(xiàn)一個(gè)區(qū)塊都沒安裝上。 原文:https://www.dayuzy.com/?p=481 今天折騰了一天終于把a(bǔ)nt Design Pro v4.0版本安裝完成了,問題最多的就是安裝區(qū)塊問題,官方文檔: 可以在 pro 項(xiàng)目跟目錄中...

    _ang 評論0 收藏0
  • 記一次關(guān)于sklearn.datasets.fetch_20newsgroups下載速度極慢解決

    摘要:明天就是中秋節(jié)了現(xiàn)在的實(shí)驗(yàn)室空空蕩蕩的只剩下我們幾個(gè)了提前祝大家中秋快樂 最近, 耗子我在做關(guān)于互聯(lián)網(wǎng)新聞分類的項(xiàng)目, 需要用到sklearn.datasets里新聞數(shù)據(jù)抓取器fetch_20newsgroups, 而當(dāng)將參數(shù)subset設(shè)置為all時(shí), fetch_20newsgroups需要即時(shí)從互聯(lián)網(wǎng)下載數(shù)據(jù), So: showImg(https://segmentfault.c...

    dabai 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<