fetch ios低版本兼容cannot clone a disturbed response
2021/9/9 23:05:51
本文主要是介绍fetch ios低版本兼容cannot clone a disturbed response,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
报错信息
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的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-08CCPM如何缩短项目周期并降低风险?
- 2025-01-08Omnivore 替代品 Readeck 安装与使用教程
- 2025-01-07Cursor 收费太贵?3分钟教你接入超低价 DeepSeek-V3,代码质量逼近 Claude 3.5
- 2025-01-06PingCAP 连续两年入选 Gartner 云数据库管理系统魔力象限“荣誉提及”
- 2025-01-05Easysearch 可搜索快照功能,看这篇就够了
- 2025-01-04BOT+EPC模式在基础设施项目中的应用与优势
- 2025-01-03用LangChain构建会检索和搜索的智能聊天机器人指南
- 2025-01-03图像文字理解,OCR、大模型还是多模态模型?PalliGema2在QLoRA技术上的微调与应用
- 2025-01-03混合搜索:用LanceDB实现语义和关键词结合的搜索技术(应用于实际项目)
- 2025-01-03停止思考数据管道,开始构建数据平台:介绍Analytics Engineering Framework