最近做的微信小程序中有"Ai对话"需求,其中重要的一点就是流式响应,现分享处理逻辑。
微信小程序请求不支持接受stream流
开始时尝试在wx.request
方法请求体中加入responseType: 'stream'
等方法进行实现,发现在 success
回调中,并不是实时返回的,而是最后的完整结果。显然这种方法不行~
而后找到了真正的可行方案:onChunkReceived
也就是在小程序中发起请求时,开启 enableChunked
,并监听onChunkReceived
的回调,进行数据处理
代码实现
js
const requestTask = wx.request({
url: 'xxx',
method: 'GET',
responseType: "arraybuffer",
enableChunked: true, //关键!开启流式传输模式
header: {
'content-type': 'application/json',
},
data: {
"prompt": '我梦见了一只金毛抢我的篮球',
},
success: (res) => {
console.log("结束----request success", res);
},
fail: (err) => {
console.log("request fail", err);
},
});
// 监听请求头接受事件
requestTask.onHeadersReceived(r => {
});
// 监听数据分块接收事件
requestTask.onChunkReceived((response) => {
console.log('response',response)
// 收到流式数据,根据返回值进行相对应数据解码
let data16 = app.buf2hex(response.data)
let responseText = app.hexToStr(data16)
// 将处理好的字符串加入到数据中
this.setData({
text: this.data.text + responseText
})
});
以上,就解决了我们的流式传输问题。
顺便分享下自己解码时用到的两个方法
js
/**
* 将 ArrayBuffer 转换为十六进制字符串
* @param {ArrayBuffer} buffer - 待转换的 ArrayBuffer
* @returns {string} - 转换后的十六进制字符串
*/
buf2hex(buffer) {
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
},
/**
* 将十六进制字符串转换为普通字符串
* @param {string} hex - 十六进制字符串
* @returns {string} - 转换后的普通字符串
*/
hexToStr(hex) {
let str = '';
for (let i = 0; i < hex.length; i += 2) {
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
}
return str;
}