收藏
回答

微信开发者工具 enableChunked 为 true 和 false 返回数据不一样

框架类型 问题类型 操作系统 工具版本
小程序 Bug macOS 1.06.2303060

问题描述:

微信开发者工具中,当接口返回数据为二进制编码的字符串,且原始字符串含有非 ASCII 字符时,enableChunked 为 true 和 false 返回数据不一样。

真机没有这个问题。

复现步骤:

我们的服务器会以 'Transfer-Encoding': 'chunked' 的方式返回二进制数据,数据内容为编码后的字符串。

示例服务器实现:

const http = require('http');

const server = http.createServer((req, res) => {
  const encoder = new TextEncoder();
  res.writeHead(200, {
    'Transfer-Encoding': 'chunked',
  });
  const data = encoder.encode('你好'); // 当原始内容包含非 ASCII 字符的时候触发这个 bug
  // data is Uint8Array [228, 189, 160, 229, 165, 189]
  res.write(data);
  res.end();
});

server.listen(8000, () => {
  console.log('Server running on port 8000');
});


在使用小程序的 request 接口访问这个接口时,如果不设置 enableChunked,在 sucess 回调中获取的数据是正常的,并且可以正确 decode。

wx.request({
  url: 'http://localhost:8000',
  responseType: 'arraybuffer',
  enableChunked: false
  success: (res) => {
    console.log(new Uint8Array(res.data));
    // Uint8Array [228, 189, 160, 229, 165, 189] 正确,跟服务端发出的一样
  },
});


如果设置 enableChunked 为 false,在 onChunkReceived 回调中获取的数据时错误的,并且无法正确 decode

const task = wx.request({
  url: 'http://localhost:8000',
  responseType: 'arraybuffer',
  enableChunked: true
});

task.onChunkReceived((res) => {
  console.log(new Uint8Array(res.data)); 
  // Uint8Array [96, 125] 错误,跟服务端发出的不一样
})


说明:

  1. 这个问题只在开发者工具上发现,真机没有这个问题。
  2. 只有原始字符串包含非 ASCII 字符的时候会出现这个问题。比如把“你好”换成“Hello”就没事


最后一次编辑于  2023-05-15
回答关注问题邀请回答
收藏

1 个回答

  • 张晨  🔆
    张晨 🔆
    2023-05-16

    这里的原因是工具使用浏览器XHR的能力去实现wx.request

    当type是arraybuffer的时候,XHR的onProgress就会为null.

    所以工具侧会强制走xhr.responseType = 'text'

    https://stackoverflow.com/questions/55393775/javascript-xmlhttprequest-responsetype-as-arraybuffer-how-to-get-current-ar

    两者确实有差异,目前不太好解决。

    2023-05-16
    有用 1
    回复 3
    • 王成
      王成
      2023-05-18
      可以用 fetch 吗?在浏览器上用 fetch + ReadableStream 是可以得到正确的数据的。
      2023-05-18
      回复
    • 张晨  🔆
      张晨 🔆
      2023-05-18回复王成
      我这边研究一下
      2023-05-18
      1
      回复
    • 杨帆 - AI 打工人
      杨帆 - AI 打工人
      2023-06-06
      你好,我有一个类似这个题主的问题想要请教一下您:我用 fastAPI 写了一个 streamingResponse 的接口,用 wx.request 读取的时候报错:timeout,其中 fastAPI 后端接口代码:
      def fake_data_streamer(query):
          for i in range(10):
              yield f'some fake query data: {query}\t'
              time.sleep(0.5)
      @app.get("/test_fake_stream")
      async def test_fake_stream(query: str):


          print(f"=> fake_data_streamer")
          rs = fake_data_streamer(query=query)
          # set streaming header
          headers = {
              'Transfer-Encoding': 'chunked',
              'Cache-Control': 'no-cache',
              'Connection': 'keep-alive',
              # 'Content-Type': 'text/plain',
          }
          return StreamingResponse(
              rs,
              media_type='text/event-stream',
              headers=headers
          ) 
      ' 是双引号,复制到这里就变成了#39,
      微信小程序端 wx.request 代码为:
          const request_url = 'https://chat.aichat.vin/test_fake_stream';
          var requestTask = wx.request({
            url: request_url,
            method: 'get',
            data: {
              query: 'hi'
            },
            enableChunked: true,
            success: response => {
              console.log('API response:');
              console.log(response)
            },
            fail: function(error) {
              console.log('Error:', error);
            },
            complete: function(res) {console.log(res)},
          });
          requestTask.onChunkReceived(res => {
            console.log("onChunkReceived:")
            console.log(res, res.data)
          });
      大佬有空的话麻烦看一下哈,感谢!
      2023-06-06
      回复
登录 后发表内容