fetch ios低版本兼容cannot clone a disturbed response
报错信息
ios 11以下 cannot clone a disturbed response
问题发生场景
- 使用了一个或者多个三方库
- 三方库或者自己的业务代码重写了fetch
- ios11以下
核心原因 ios低版本兼容问题,fetch的原始响应clone一次解析后,不能再次clone(浏览器报错信息:cannot clone a disturbed response)
我们使用fetch的响应的时候,如果直接通过方法解析2次,第二次就会报错 body stream already read
fetch("/").then(res=>{
res.text().then((r)=>{console.log(r)})
res.text().then((r)=>{console.log(r)})
});
所以一般会使用clone,如下的写法。这样的写法有兼容问题,ios11以下会报错: cannot clone a disturbed response
fetch("/").then(res=>{
res.clone().text().then((r)=>{console.log(r)})
res.clone().text().then((r)=>{console.log(r)})
});
这个时候有同学会问了,谁会这样写啊,一般解析一次就够了,干嘛解析两次。如果使用了三方库就会出现这种问题,一般三方库会重写fetch的。三方库可能是请求库(axois、umi-request),也可能是调试库(eduda、vconsole),等等。三方库,会重写fetch,为了拦截API写点自己需要的代码,大概是下面这样的:
// 三方库重写fetch代码
const originFetch = fetch;
fetch = function(){
// do some
return originFetch
.apply(this, arguments)
.then((res) => {
// do some
res.clone().text().then((data) => {
// do some
})
return res
})
}
// 业务代码
fetch('/').then(res=>{
res.clone().text()
})
如上代码,返回的 res 已经被三方库 clone 过了,如果再次 clone 便会出现ios11以下的兼容报错。所以我们的业务代码会直接报错,拿不到任何响应。
三方库分析
umi/request
umi/request,发现了这个问题,并且做了代码的处理. ( github.com/umijs/umi-r… )
从目前的代码看起来,这个解决方案只是解决了它内部使用的问题,而且它返回的数据并不是fetch的原始响应,而是它解析后的接口结果。
现在假如我们在umi/request之后,再实例化使用vconsle,或者eruda,这两个库会重写fetch。两个库同时存在的时候,res.clone 就会触发开始说的ios低版本问题。
vconsole
下面这段是vconsole的fetch代码
eruda
几乎大多的库都如上面,fetch返回的原始响应在库内部被clone过后,原始响应再流转下去。流转下去以后其他的三方库或者业务代码,执行clone便会触发ios11以下的兼容问题。就像是执行了下面的代码一样。
fetch("/").then(res=>{
// 第一次clone
res.clone().text().then((r)=>{console.log(r)})
return res
}).then(res=>{
// 第二次clone
res.clone().text().then((r)=>{console.log(r)})
});
解决方案
如果业务代码使用原生fetch只会解析一次fetch响应,可以忽略因为不会触发两次clone。 作为三方库的开发者,应该知道有这样的兼容问题,下面的写法ios11以下也不会有问题。
fetch("/").then(res=>{
// 第一次clone
const C1 = res.clone();
const C2 = res.clone();
C1.clone().text().then((r)=>{console.log(r)})
C2.clone().text().then((r)=>{console.log(r)})
})
// else
fetch("/").then(res=>{
// 第一次clone
const C1 = res.clone();
C1.clone().text().then((r)=>{console.log(r)})
C1.clone().text().then((r)=>{console.log(r)})
})
// else...
理一下关系
会出兼容性问题的写法图示
解决方案图示
我们多clone一级,就能解决这个问题,这和clone本身的意义实际有出处。ios11以下的这个兼容问题,应该是以前的bug,这个bug在ios11以后才修复,总之现在这样就能解决问题。
解决方案已经明确了,三方库推荐如下方式修改clone方法。
const originFetch = fetch;
fetch = function(){
// do some
return originFetch
.apply(this, arguments)
.then((res) => {
const copyClone = res.clone();
// do some
copyClone.clone().text().then((data) => {
// do some
})
return copyClone.clone()
})
}
如果同时引入多个三方库,其中一个已经按照下面写法解决了兼容性问题,一个还没有解决,可以让解决了兼容的库先执行,也能保证运行正常。
同时还发现,ios11以下,fetch finally方法undefined,不能使用finally方法
ps: 水印就不去了,先在掘金编辑的,拷贝过来多平台发布,本文章为原创文。
fetch ios低版本兼容cannot clone a disturbed response的更多相关文章
- Material Designer的低版本兼容实现(五)—— ActivityOptionsCompat
extends:http://www.cnblogs.com/tianzhijiexian/p/4087917.html 本文是对API中的方法做了介绍,如果想要看如何让这些方法兼容4.x或2.x可以 ...
- Material Designer的低版本兼容实现(一)—— 简介 & 目录
很长一段时间没写东西了,其实是因为最近在研究Material Designer这个东西,熬夜熬的身体也不是很好了.所以就偷懒没写东西,这回开的这个系列文章是讲如何将Material Designer在 ...
- IE低版本兼容的感悟
2017-04-09 曾经折磨一代人的兼容问题,如今也在同样折磨着我们,明明可以做JS判断来避免对ie低版本的兼容,但是却还是耐心的做着兼容,你可能会问这是为什么, 我们调的不是兼容,是整整一代人的情 ...
- Material Designer的低版本兼容实现(二)—— Theme
Theme material主题可以定义为如下形式: @android:style/Theme.Material @android:style/Theme.Material.Light @androi ...
- javascript原生bind方法ie低版本兼容详解
上一篇文章讲到了javascript原生的bind方法: http://www.cnblogs.com/liulangmao/p/3451669.html 这篇文章就在理解了原生bind方法的原理以后 ...
- Material Designer的低版本兼容实现(十)—— CheckBox & RadioButton
ChekBox的用途我们就不必多说了,算是一个很古老的控件了,何其类似的还有RadioButton,这个东西因为我目前还没写出来,所以用了别人的一个lib,这下面会说到.顺便说一句,如果你的app是在 ...
- es6语法在ios低版本的支持性
let.const.箭头函数在ios的某些版本不支持,会引起报错 参考:https://blog.csdn.net/cx091/article/details/79805369 https://can ...
- Material Designer的低版本兼容实现(十二)—— Slider or SeekBar
Slider,我更喜欢叫他SeekBar,其实是一个东西啦,就是拖动条.5.0的拖动条和4.x上的HOLO风格完全不同,平添了一些精致.此外还加入了数值指示器,让用户在滑动的时候就能知道现在到了什么位 ...
- Material Designer的低版本兼容实现(十一)—— Switch
5.0中的switch和之前完全不同了,漂亮不漂亮咱们另说,总之4.x上是没有这样的效果了.实现方式有两种,一种是用这个兼容包来做类似的效果,一种是用传统的checkbox来代替.我感觉兼容包的效果是 ...
随机推荐
- intouch 开发源程序加密方法
在先前项目中,因为同行竞争被拷贝走了源程序代码,以至于被上司责备,故而亡羊补牢对intouch(10.1老版本进行源代码加密探索)整理方法如下. 1.intouch wondermarker打开源程序 ...
- ajax 提交序列化表单
1.提交序列化表单+参数: var a = $.param({'address':address,'delivity':delivity,'payment':payment}) + '&' + ...
- vue使用GraphVis开发无限拓展的关系图谱
1.去GraphVis官网下载对应的js,新版和旧版的js有所不同,看自己需求引入旧版还是新版(GraphVis官方网址:http://www.graphvis.cn/) visgraph.min.j ...
- 配置多个git用的ssh key
参考 http://www.sail.name/2018/12/16/ssh-config-of-mac/ 有一点注意 Host 的名字和 HostName改为一致. 因为从git仓库复制的地址是全程 ...
- GPB重磅!浙大李兰娟院士团队修饰多组学研究揭示炎症反应新机制
炎症 (inflammation) 是机体对致炎因子的损伤所发生的一种以防御反应为主的基本病理过程.翻译后修饰(PTMs)在调节多种炎症信号通路中起着重要作用,如磷酸化(phosphorylation ...
- 智能合约审计-不安全的delegatecall
简介 当合约A以delegatecall方式调用时, 相当于将外部合约B的func()代码复制过来 (其函数中涉及的变量或函数都需要在本地存在), 在合约A上下文空间中执行. 合约 pragma so ...
- 你的ES数据备份了吗?
前言: 无论使用哪种存储软件,定期的备份数据都是重中之重,在使用ElasticSearch的时候,随着数据日益积累,存放es数据的磁盘空间也捉襟见肘, 此时对于业务功能使用不到的索引数据,又不能直接删 ...
- shell趣味实验——图形
目录 一.直线 二.矩形 2.1.镂空矩形 三.直角三角形 3.1.倒直角三角形 3.2.反直角三角形 3.3.等腰三角形 3.4.倒等腰三角形 3.5.菱形 四.平行四边形 五.梯形 5.1.等腰梯 ...
- Java LinkedList【笔记】
Java LinkedList[笔记] LinkedList LinkedList 适用于要求有顺序,并且会按照顺序进行迭代的场景,依赖于底层的链表结构 LinkedList基本结构 LinkedLi ...
- efcore分表下"完美"实现
ShardingCore 如何呈现"完美"分表 这篇文章是我针对efcore的分表的简单介绍,如果您有以下需求那么可以自己选择是否使用本框架,本框架将一直持续更新下去,并且免费开源 ...