微信小程序中实现流式传输

最近公司在All in AI我之前负责的小程序就需要接入 deepSeek。公司其它的小程序使用的都是 webview 嵌套的 h5+浏览器原生的 fetch(流式传输)来实现的。但是在小程序中并没有 fetch 请求,因此无法使用。

什么是流式传输?

在解决问题之前,我们需要了解什么是流式传输。流式传输指的是将数据分成多个数据流,通过网络传输,以减少网络延迟和提高性能。在某些情况下,流式传输也可以用于将视频流和音频流传输到客户端。流式传输是一种高效的数据传输方式,常用于大文件下载和在线视频播放等。

解决方案

微信官方文档中提到,wx.request中支持onChunkReceived分段式传输,在小程序中发起请求时,开启 enableChunked,并监听onChunkReceived的回调,逐步处理接收到的数据块,并将处理好的字符串逐步加入到数据中。这种方式有效地应对了微信小程序请求不支持 stream 流的问题。
注意:如果使用了 uniapp,那么请使用wx.request,而不要使用uni.request。uniapp封装过后的流式无法处理流式数据。

代码实现

const requestTask = wx.request({
          url: `${config.baseUrl}/ai/deepSeek`,
          header: {
            "X-Access-Token": uni.$storage.get("token"),
          },
          data: JSON.stringify({
            question: this.question,
            appIdconfig.APP_ID,
            userName: 'xxx'
          }),
          method: "POST",
          enableChunked: true,   // 开启流式传输
          responseType: "arraybuffer",
        });

        if (requestTask?.onChunkReceived) {
          requestTask.onChunkReceived(this.handleChunkData);
        } else {
          // 如果 onChunkReceived 不存在,则使用普通的请求方式
          this.normalRequest();
        }

// 分块数据处理
    handleChunkData(res) {
      try {
        let rawStr = "";
        // 微信小程序专用ArrayBuffer转字符串
        rawStr = wx.arrayBufferToBase64(res.data);
        rawStr = this.base64ToUtf8(rawStr);

        // 手动UTF-8解码,微信小程序存在兼容问题
        rawStr = Array.from(new Uint8Array(res.data))
          .map((byte) => String.fromCharCode(byte))
          .join("");
        // 中文特殊处理
        rawStr = unescape(encodeURIComponent(rawStr));
        const chunkJson = rawStr.split("data:  ")[1];
        const rawData = JSON.parse(chunkJson);
        // 直接拼接有效内容
        const text = rawData.choices?.[0]?.delta?.content;
        // 移除think部分的内容,通过</think>来做标识
        if (text == "</think>") {
          this.isThink = false;
        }
        // 根据自己的业务来做处理
        if (!this.isThink) {
          const tx = text.replace("</think>", "");
          this.streamBuffer += tx;

          // 实时更新最新内容(自动Markdown转换)
          const answer = this.list[this.list.length - 1];
          let render = markdown.render(this.streamBuffer);
          answer.content = render;
          // 优化性能的节流更新
          this.throttleUpdate();
        }
      } catch (e) {
        console.error("数据处理异常:", e);
      }
    }
// 辅助函数,根据项目内容自己调整
  // 之前使用的textDocode,但是微信小程序存在兼容问题,所以改用ArrayBuffer转字符串
   base64ToUtf8(base64Str) {
      return this.wechatBase64Decode(base64Str);
    },

    wechatBase64Decode(base64Str) {
      const arr = wx.base64ToArrayBuffer(base64Str);
      return this.arrayBufferToString(arr);
    },

    browserBase64Decode(base64Str) {
      const binaryStr = atob(base64Str);
      const bytes = new Uint8Array(binaryStr.length);
      for (let i = 0; i < binaryStr.length; i++) {
        bytes[i] = binaryStr.charCodeAt(i);
      }
      return this.arrayBufferToString(bytes.buffer);
    },

    arrayBufferToString(buffer) {
      try {
        return new TextDecoder("utf-8").decode(buffer);
      } catch (e) {
        let str = "";
        new Uint8Array(buffer).forEach((byte) => {
          str += String.fromCharCode(byte);
        });
        return decodeURIComponent(escape(str));
      }
    },
    // // 节流更新
    throttleUpdate() {
      if (!this.updateTimer) {
        this.updateTimer = setTimeout(() => {
          this.$forceUpdate();
          this.scrollToBottom();
          this.updateTimer = null;
        }, 500);
      }
    }

要点 1: 将 enableChunked 设置为 true
要点 2: 监听 onChunkReceived 的回调
要点 3: 使用markdown-it解析数据

待优化项

  • 由于小程序没有提供onReceivedEnd事件,因此无法得知当前消息是否发送完毕,只能通过返回返回字段中的特殊标识符来判断当前是否已发送完毕(需要和后端约束)。以此来动态设置当前这一则消息的loading加载状态。
  • deepSeek深度思考返回的结果中包含了大量的think内容,对于当前场景中,并不需要展示think部分的内容,做一部分内容筛减,只有当匹配到think结束符时才向stringBuffer中填充文本内容。
  • markdown-it在解析时需要确保文内内容符合解析规则,根据返回结果动态调整内容,否则页面可能无法展示。

结束语

通过在请求中设置enableChunked: true和监听onChunkReceived回调,解决了微信小程序中不支持 stream 流的流式传输问题。

以上,就解决了我们的流式传输问题,后面会分享在h5中实现流式数据处理的方法。

posted @   含若飞  阅读(91)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示