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

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

fetch默認不攜帶cookie

配置其 credentials 項,其有3個值:react

  • omit: 默認值,忽略cookie的發送
  • same-origin: 表示cookie只能同域發送,不能跨域發送
  • include: cookie既能夠同域發送,也能夠跨域發送

credentials所表達的含義,其實與XHR2中的withCredentials屬性相似,表示請求是否攜帶cookiegit

這樣,若要fetch請求攜帶cookie信息,只需設置一下credentials選項便可,例如fetch(url, {credentials: 'include'});github

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

這主要是由fetch返回promise致使的,由於fetch返回的promise在某些錯誤的http狀態下如400、500等不會reject,相反它會被resolve;只有網絡錯誤會致使請求不能完成時,fetch 纔會被 reject;因此通常會對fetch請求作一層封裝,例以下面代碼所示:npm

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處理

方法一:單純setTimeout方式json

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功能:segmentfault

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])
}
複製代碼

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是不支持有關progress事件的;不過可喜的是,根據fetch的指導規範標準,其內部設計實現了Request和Response類;其中Response封裝一些方法和屬性,經過Response實例能夠訪問這些方法和屬性,例如response.json()、response.body等等;

值得關注的地方是,response.body是一個可讀字節流對象,其實現了一個getRender()方法,其具體做用是:

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

所以,利用到這點能夠模擬出fetch的progress

// 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);
  });
});
複製代碼

fetch跨域問題

fetch的mode配置項有3個值,以下:

  • same-origin:該模式是不容許跨域的,它須要遵照同源策略,不然瀏覽器會返回一個error告知不能跨域;其對應的response type爲basic。

  • cors: 該模式支持跨域請求,顧名思義它是以CORS的形式跨域;固然該模式也能夠同域請求不須要後端額外的CORS支持;其對應的response type爲cors。

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

參考

友情連接

相關文章
相關標籤/搜索