博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
fetch使用的常见问题及其解决办法
阅读量:5876 次
发布时间:2019-06-19

本文共 4673 字,大约阅读时间需要 15 分钟。

首先声明一下,本文不是要讲解fetch的具体用法,不清楚的可以参考 教程。

fetch默认不携带cookie

配置其 credentials 项,其有3个值:

  • omit: 默认值,忽略cookie的发送
  • same-origin: 表示cookie只能同域发送,不能跨域发送
  • include: cookie既可以同域发送,也可以跨域发送

credentials所表达的含义,其实与XHR2中的withCredentials属性类似,表示请求是否携带cookie

这样,若要fetch请求携带cookie信息,只需设置一下credentials选项即可,例如fetch(url, {credentials: 'include'});

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

方法一:单纯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])}复制代码

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 receivedfetch(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。

参考

友情链接

转载于:https://juejin.im/post/5cf09682f265da1b8811c283

你可能感兴趣的文章
4.单链表的创建和建立
查看>>
Android 好看的搜索界面,大赞Animation
查看>>
查询反模式 - GroupBy、HAVING的理解
查看>>
上班族的坐姿
查看>>
ubuntu 12.04 下面安装vmware workstation 8.0.4
查看>>
[原创]FineUI秘密花园(二十三) — 树控件概述
查看>>
【Java学习笔记】如何写一个简单的Web Service
查看>>
如何解决This system is not registered with RHN.
查看>>
Cocos2d-x学习笔记(两)Cocos2d-x总体框架
查看>>
拆解探索MagSafe电源接口结构和指示灯变颜色原理
查看>>
Android中EditText,Button等控件的设置
查看>>
lintcode:Remove Nth Node From End of Lis 删除链表中倒数第n个节点
查看>>
POJ 1915-Knight Moves (单向BFS &amp;&amp; 双向BFS 比)
查看>>
linux编译安装LAMP
查看>>
php中的continue用法
查看>>
Android小游戏应用---撕破美女衣服游戏
查看>>
TextKit简单示例
查看>>
网格最短路径算法(Dijkstra & Fast Marching)(转)
查看>>
最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)
查看>>
软链接和硬链接详解
查看>>