资讯专栏INFORMATION COLUMN

fetch使用的常见问题及其解决办法

pkwenda / 1462人阅读

摘要:首先声明一下,本文不是要讲解的具体用法,不清楚的可以参考教程。该模式用于跨域请求但是服务器不带响应头,也就是服务端不支持这也是的特殊跨域请求方式其对应的为。

首先声明一下,本文不是要讲解fetch的具体用法,不清楚的可以参考 MDN 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 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。

参考

MDN-ReadableStream

MDN fetch

https://segmentfault.com/a/1190000008484070#articleHeader3

友情链接

前端知识体系

react服务端渲染博客

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104284.html

相关文章

  • fetch使用常见问题及其解决办法

    首先声明一下,本文不是要讲解fetch的具体用法,不清楚的可以参考MDN fetch教程。 引言 说道fetch就不得不提XMLHttpRequest了,XHR在发送web请求时需要开发者配置相关请求信息和成功后的回调,尽管开发者只关心请求成功后的业务处理,但是也要配置其他繁琐内容,导致配置和调用比较混乱,也不符合关注分离的原则;fetch的出现正是为了解决XHR存在的这些问题。例如下面代码: f...

    pubdreamcc 评论0 收藏0
  • CoderPad-基于React全家桶写作/新闻一体综合应用实践总结

    摘要:基于全家桶写作新闻一体综合应用的实践总结在线地址大家伙儿们,又见面了。参照但不可否认非常符合的思想,都在处理大规模数据时彰显优势。最好的办法是使用部署环境。细致的拆分,解耦性更好,以为单位进行修改时,大大降低误伤率的同时,隔离无关的信息。 ?CoderPad-基于React全家桶写作/新闻一体综合应用的实践总结 showImg(https://segmentfault.com/img/...

    DC_er 评论0 收藏0
  • Spring Boot QuickStart (5) - Spring Data JPA

    摘要:关联关系的关联关系定义上,感觉并不是很灵活,姿势也比较难找。如,定义在关联关系上的参数可以设置级联的相关东西。因为序列化会涉及到实体类关联对象的获取,会触发所有的关联关系。 接(4) - Database 系列. Java Persistence API,可以理解就是 Java 一个持久化标准或规范,Spring Data JPA 是对它的实现。并且提供多个 JPA 厂商适配,如 Hi...

    sutaking 评论0 收藏0
  • ant Design Pro区块安装npm run fetch:blocks问题解决

    摘要:原文今天折腾了一天终于把版本安装完成了,问题最多的就是安装区块问题,官方文档可以在项目跟目录中执行来下载所有的区块。得到的界面将与中相同。此时,打开下面发现一个区块都没安装上。 原文:https://www.dayuzy.com/?p=481 今天折腾了一天终于把ant Design Pro v4.0版本安装完成了,问题最多的就是安装区块问题,官方文档: 可以在 pro 项目跟目录中...

    _ang 评论0 收藏0
  • 记一次关于sklearn.datasets.fetch_20newsgroups下载速度极慢解决

    摘要:明天就是中秋节了现在的实验室空空荡荡的只剩下我们几个了提前祝大家中秋快乐 最近, 耗子我在做关于互联网新闻分类的项目, 需要用到sklearn.datasets里新闻数据抓取器fetch_20newsgroups, 而当将参数subset设置为all时, fetch_20newsgroups需要即时从互联网下载数据, So: showImg(https://segmentfault.c...

    dabai 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<