这里的每个人都在正确的轨道上,但要解决问题,你不能打电话给.setEncoding()
EVER。
如果您调用.setEncoding()
,它将创建一个StringDecoder
并将其设置为默认解码器。如果您尝试通过null
or undefined
,那么它仍然会StringDecoder
使用其默认解码器创建一个UTF-8
. 即使你打电话.setEncoding('binary')
,也和打电话一样.setEncoding('latin1')
。是的,认真的。
我希望我可以说您设置._readableState.encoding
并_readableState.decoder
返回到null
,但是当您调用.setEncoding()
缓冲区时,它会被擦除并替换为之前已解码字符串的二进制编码。这意味着您的数据已经更改。
如果要“撤消”解码,则必须将数据流重新编码回二进制,如下所示:
req.on('data', (chunk) => {
let buffer;
if (typeof chunk === 'string') {
buffer = Buffer.from(chunk, req.readableEncoding);
} else {
buffer = chunk;
}
// Handle chunk
});
当然,如果您从不调用.setEncoding()
,那么您不必担心该块会以string
.
在您将块设置为Buffer
之后,您可以按照自己的选择使用它。出于对彻底性的兴趣,这里是如何使用预设的缓冲区大小,同时还要检查Content-Length
:
const BUFFER_SIZE = 4096;
/**
* @param {IncomingMessage} req
* @return {Promise<Buffer>}
*/
function readEntireRequest(req) {
return new Promise((resolve, reject) => {
const expectedSize = parseInt(req.headers['content-length'], 10) || null;
let data = Buffer.alloc(Math.min(BUFFER_SIZE, expectedSize || BUFFER_SIZE));
let bytesWritten = 0;
req.on('data', (chunk) => {
if ((chunk.length + bytesWritten) > data.length) {
// Buffer is too small. Double it.
let newLength = data.length * 2;
while (newLength < chunk.length + data.length) {
newLength *= 2;
}
const newBuffer = Buffer.alloc(newLength);
data.copy(newBuffer);
data = newBuffer;
}
bytesWritten += chunk.copy(data, bytesWritten);
if (bytesWritten === expectedSize) {
// If we trust Content-Length, we could return immediately here.
}
});
req.on('end', () => {
if (data.length > bytesWritten) {
// Return a slice of the original buffer
data = data.subarray(0, bytesWritten);
}
resolve(data);
});
req.on('error', (err) => {
reject(err);
});
});
}
此处使用缓冲区大小的选择是为了避免立即保留大量内存,而是仅根据需要获取 RAM。该Promise
功能只是为了方便。