一.实现逻辑
1.使用 wx.request 开启流式输出(当然后端 也要开启 transfer-encoding: chunked)有些后端会默认开启
this.requestTask = wx.request({
url: 'xxxxxx',
enableChunked: true, //开启 transfer-encoding chunked。
method: 'POST',
header: {
'content-type': 'application/json',
Authorization: `Bearer ${this.data.token}`
},
data: {
question: message
}
})
2.使用 onChunkReceived 来监听返回的数据
this.requestTask.onChunkReceived((res) => {
console.log(res.data, 888)
const parsed = this.decodeUint8Array(res.data)
const temp = this.extractContentFromStream(parsed)
console.log(temp)//转换之后的内容
})
3.处理sse返回的数据(默认返回的是 ArrayBuffer(87) {} )
import encoding from '../../utils/encoding.js'
decodeUint8Array(uint8Array) {
const data16 = this.buf2hex(uint8Array)
const requestData = this.hexToStr(data16)
return requestData
},
buf2hex(arrayBuffer) {
return Array.prototype.map.call(new Uint8Array(arrayBuffer), (x) => ('00' + x.toString(16)).slice(-2)).join('')
},
hexToStr(hex) {
let trimedStr = hex.trim()
let rawStr = trimedStr.substr(0, 2).toLowerCase() === '0x' ? trimedStr.substr(2) : trimedStr
let len = rawStr.length
if (len % 2 !== 0) {
return ''
}
let curCharCode
let resultStr = []
for (let i = 0; i < len; i = i + 2) {
curCharCode = parseInt(rawStr.substr(i, 2), 16)
resultStr.push(curCharCode)
}
let bytesView = new Uint8Array(resultStr)
let str = new encoding.TextDecoder().decode(bytesView)
return str
}
4.需要两个文件 encoding.js 和 encoding-indexes.js 文件
二、问题
1.微信开发者工具中的 真机调试没反应(测试机 微信版本8.0.60)
使用微信开发者工具的 预览 或者 上传体验版本 测试
2.在微信开发者工具中 即使你开启了 enableChunked: true, 数据也不是 流式返回,而是只响应了一次,一次性返回的
升级最新版本的 微信开发者工具(我是这个原因,微信开发者工具太旧)
3.这时会遇到一个新的问题:微信开发者工具是 流式返回 但是真机测试又是一次性返回。。。。当时我真是吐血 ,看了微信开放社区 和 百度 ai 都没解决方法,最后发现是 后端 Nginx 配置问题
location /products/ai/ {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
chunked_transfer_encoding on;
proxy_hide_header Content-Length;
}
后端在 nginx 加入之后 真机也能 流式返回
4.为什么会这样呢
因为后端使用的是 宝塔 ,默认会将 chunked 流式响应缓存/合并,有时即使后端返回 chunked,前端收到的却是带 Content-Length 的完整包,即是 一次性的返回数据,也就是说被 nginx 缓冲了流式输出,最终一次性返回。 上诉配置 就是 禁用缓存