zoukankan      html  css  js  c++  java
  • 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的。三方库可能是请求库(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… )

    image.png

    github.com/umijs/umi-r…

    image.png

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

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

     

    vconsole

    下面这段是vconsole的fetch代码

    image.png

     

    eruda

    github.com/liriliri/ch…

    image.png

    github.com/liriliri/ch…

    image.png

    几乎大多的库都如上面,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...

    理一下关系

    会出兼容性问题的写法图示

    image.png

    解决方案图示

    image.png

    我们多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: 水印就不去了,先在掘金编辑的,拷贝过来多平台发布,本文章为原创文。

    有没有人打赏?没有的话,那我晚点再来问问。
    关注大诗人公众号,第一时间获取最新文章。
    如果你有购买钢琴的打算,可以从这里了解到在售信息,价格实惠品质保障。

    ---转发请标明,并添加原文链接---
  • 相关阅读:
    poj 1088 滑雪
    位运算与bitset
    hdu 4607 Park Visit
    树的直径
    codeforces 495D Sonya and Matrix
    German Collegiate Programming Contest 2015(第三场)
    BAPC 2014 Preliminary(第一场)
    Benelux Algorithm Programming Contest 2014 Final(第二场)
    E. Reachability from the Capital(tarjan+dfs)
    poj2104 K-th Number(划分树)
  • 原文地址:https://www.cnblogs.com/1wen/p/15248350.html
Copyright © 2011-2022 走看看