解决微信小程序中调用流式接口,处理二进制数据时 TextDecoder 不兼容的问题

问题复现

      最近在开发一个 AI 问答小程序时,由于接口返回的是流式二进制数据,因此我使用了 TextDecoder decode 方法将二进制数据转换为文本。在开发环境中,数据处理一直没有问题,但在真机测试及上线后,发现调用接口时出现了 TextDecoder is not defined 的报错,导致数据无法正常显示。最终发现,问题出在 TextDecoder 这个 Web API 在小程序的生产环境中并不兼容。

解决方案

一开始,我尝试了很多解决 TextDecoder 兼容性问题的库,例如 text-encoding、text-encoding-polyfill 和 buffer,但都没有完全解决问题。最后,我决定手写一个 TextDecoder 的实现,并将其挂载到全局。废话不多说,直接上代码,各位大哥直接复制粘贴即可。

// TextDecoder polyfill
if (typeof TextDecoder === 'undefined') {
  class TextDecoder {
    constructor(encoding = 'utf-8') {
      this.encoding = encoding.toLowerCase();
    }

    decode(dataView) {
      let data;
      if (dataView instanceof ArrayBuffer) {
        data = new Uint8Array(dataView);
      } else if (dataView instanceof Uint8Array) {
        data = dataView;
      } else {
        throw new Error('参数必须是 ArrayBuffer 或 Uint8Array');
      }

      if (this.encoding === 'utf-8') {
        return this._decodeUTF8(data);
      } else {
        throw new Error('当前只支持 UTF-8 编码');
      }
    }

    _decodeUTF8(data) {
      let str = '';
      let i = 0;

      while (i < data.length) {
        let byte1 = data[i];
        let char;

        // ASCII 字符
        if (byte1 < 0x80) {
          char = String.fromCharCode(byte1);
          i += 1;
        }
        // 2字节序列
        else if (byte1 < 0xE0) {
          const byte2 = data[i + 1];
          char = String.fromCharCode(((byte1 & 0x1F) << 6) | (byte2 & 0x3F));
          i += 2;
        }
        // 3字节序列
        else if (byte1 < 0xF0) {
          const byte2 = data[i + 1];
          const byte3 = data[i + 2];
          char = String.fromCharCode(
            ((byte1 & 0x0F) << 12) |
            ((byte2 & 0x3F) << 6) |
            (byte3 & 0x3F)
          );
          i += 3;
        }
        // 4字节序列
        else {
          const byte2 = data[i + 1];
          const byte3 = data[i + 2];
          const byte4 = data[i + 3];
          let codepoint = ((byte1 & 0x07) << 18) |
            ((byte2 & 0x3F) << 12) |
            ((byte3 & 0x3F) << 6) |
            (byte4 & 0x3F);

          // UTF-16 surrogate pair
          codepoint -= 0x10000;
          const highSurrogate = (codepoint >> 10) + 0xD800;
          const lowSurrogate = (codepoint & 0x3FF) + 0xDC00;
          char = String.fromCharCode(highSurrogate, lowSurrogate);
          i += 4;
        }

        str += char;
      }

      return str;
    }
  }

  // 全局注入 TextDecoder
  globalThis.TextDecoder = TextDecoder;
}

新建一个 textDecoder.js 文件,将自定义的 TextDecoder 代码放入其中。然后在 app.js 中通过 import 进行导入。这样,我们的 TextDecoder 就可以在生产环境中正常使用了。

// app.js
const request = require('./utils/request')
import './utils/textDecoder'
App({
  onLaunch() {
    // 展示本地存储能力
    const logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)

    // 登录
    request.login();
  },
  globalData: {
    userInfo: null
  }
})

评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值