问题描述:
微信开发者工具中,当接口返回数据为二进制编码的字符串,且原始字符串含有非 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] 错误,跟服务端发出的不一样
})
说明:
- 这个问题只在开发者工具上发现,真机没有这个问题。
- 只有原始字符串包含非 ASCII 字符的时候会出现这个问题。比如把“你好”换成“Hello”就没事
这里的原因是工具使用浏览器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
两者确实有差异,目前不太好解决。
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)
});
大佬有空的话麻烦看一下哈,感谢!