报错信息

ios 11以下 cannot clone a disturbed response

github.com/github/fetc…

问题发生场景

  • 使用了一个或者多个三方库
  • 三方库或者自己的业务代码重写了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… )

github.com/umijs/umi-r…

从目前的代码看起来,这个解决方案只是解决了它内部使用的问题,而且它返回的数据并不是fetch的原始响应,而是它解析后的接口结果。

现在假如我们在umi/request之后,再实例化使用vconsle,或者eruda,这两个库会重写fetch。两个库同时存在的时候,res.clone 就会触发开始说的ios低版本问题。

vconsole

下面这段是vconsole的fetch代码

eruda

github.com/liriliri/ch…

github.com/liriliri/ch…

几乎大多的库都如上面,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的更多相关文章

  1. Material Designer的低版本兼容实现(五)—— ActivityOptionsCompat

    extends:http://www.cnblogs.com/tianzhijiexian/p/4087917.html 本文是对API中的方法做了介绍,如果想要看如何让这些方法兼容4.x或2.x可以 ...

  2. Material Designer的低版本兼容实现(一)—— 简介 & 目录

    很长一段时间没写东西了,其实是因为最近在研究Material Designer这个东西,熬夜熬的身体也不是很好了.所以就偷懒没写东西,这回开的这个系列文章是讲如何将Material Designer在 ...

  3. IE低版本兼容的感悟

    2017-04-09 曾经折磨一代人的兼容问题,如今也在同样折磨着我们,明明可以做JS判断来避免对ie低版本的兼容,但是却还是耐心的做着兼容,你可能会问这是为什么, 我们调的不是兼容,是整整一代人的情 ...

  4. Material Designer的低版本兼容实现(二)—— Theme

    Theme material主题可以定义为如下形式: @android:style/Theme.Material @android:style/Theme.Material.Light @androi ...

  5. javascript原生bind方法ie低版本兼容详解

    上一篇文章讲到了javascript原生的bind方法: http://www.cnblogs.com/liulangmao/p/3451669.html 这篇文章就在理解了原生bind方法的原理以后 ...

  6. Material Designer的低版本兼容实现(十)—— CheckBox & RadioButton

    ChekBox的用途我们就不必多说了,算是一个很古老的控件了,何其类似的还有RadioButton,这个东西因为我目前还没写出来,所以用了别人的一个lib,这下面会说到.顺便说一句,如果你的app是在 ...

  7. es6语法在ios低版本的支持性

    let.const.箭头函数在ios的某些版本不支持,会引起报错 参考:https://blog.csdn.net/cx091/article/details/79805369 https://can ...

  8. Material Designer的低版本兼容实现(十二)—— Slider or SeekBar

    Slider,我更喜欢叫他SeekBar,其实是一个东西啦,就是拖动条.5.0的拖动条和4.x上的HOLO风格完全不同,平添了一些精致.此外还加入了数值指示器,让用户在滑动的时候就能知道现在到了什么位 ...

  9. Material Designer的低版本兼容实现(十一)—— Switch

    5.0中的switch和之前完全不同了,漂亮不漂亮咱们另说,总之4.x上是没有这样的效果了.实现方式有两种,一种是用这个兼容包来做类似的效果,一种是用传统的checkbox来代替.我感觉兼容包的效果是 ...

随机推荐

  1. centos7网卡配置文件

    HWADDR=00:0c:29:a7:8e:ee TYPE=Ethernet BOOTPROTO=staticDEFROUTE=yes PEERROUTES=yesPEERROUTES=yes IPV ...

  2. AT指令集及其通信测试方式

    1 前言 AT即Attention,AT指令集是从终端设备(Terminal Equipment,TE)向终端适配器(Terminal Adapter, TA)发送的.通过TA,TE发送AT指令来控制 ...

  3. springboot 中 inputStream 神秘消失之谜

    序言 最近小明接手了前同事的代码,意料之外.情理之中的遇到了坑. 为了避免掉入同一个坑两次,小明决定把这个坑记下来,并在坑前立一个大牌子,避免其他小伙伴掉进去. HTTPClient 模拟调用 为了把 ...

  4. linux笔记全(无图版)

    1.ls 查看当前目录下的所有内容 黑色的是文件,蓝色的是文件夹,也就是目录 2.rm -f anaconda-ks. cfg 彻底删除文件(如不确定,则需要先保存备份,也就是快照) 3.ifconf ...

  5. C++员工管理系统(封装+多态+继承+分类化+函数调用+读写文件+指针+升序降序算法等一系列知识结合)

    1 C++职工管理系统 2 该项目实现 八个 功能 3 1-增加功能 2-显示功能 3-删除功能 4-修改功能 4 5-查找功能 6-排序功能 7-清空功能 8-退出功能 5 实现多个功能使用了多个C ...

  6. 树莓派3B/3B+/4B 刷机装系统烧录镜像教程

    树莓派3B/3B+/4B 刷机装系统烧录镜像教程 树莓派 背景故事 刚拿到树莓派的第一件事,应该就是要装系统了,那么应该怎么操作呢?下面就给大家介绍一下吧. 硬件准备 树莓派:3B/3B+/4B,本教 ...

  7. Linux命令(八)之安装Jdk、Tomcat

    .personSunflowerP { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); ...

  8. Apache Druid 远程代码执行 CVE-2021-25646 漏洞复现

    Apache Druid 远程代码执行 CVE-2021-25646 漏洞复现 前言 Apache Druid 是用Java编写的面向列的开源分布式数据存储,旨在快速获取大量事件数据,并在数据之上提供 ...

  9. 常见web中间件漏洞(二)Apache漏洞

    Apache(总联想到武直那个)是最常见,使用人数最多的一款web服务器软件.跨平台,多扩展,开源,用过的人都说好 Apache的漏洞主要集中在解析漏洞这一块 1.未知扩展名解析漏洞 Apache的一 ...

  10. STM32—中断详解(配合按键中断代码,代码亲测)

    在STM32中执行中断主要分三部分: 1.配置NVIC_Config()函数 2.配置EXTI_Config()函数 3.编写中断服务函数 (注:本文章所用代码为中断按键代码,实现了按键进入中断从而控 ...