大家的回答都没错,但是为了澄清问题,你不能调用.setEncoding()
。
如果你调用了.setEncoding()
,它将创建一个StringDecoder
并将其设置为默认解码器。如果你尝试传递null
或undefined
,它仍将创建一个带有默认解码器UTF-8
的StringDecoder
。即使你调用.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;
}
});
当然,如果你从未调用.setEncoding()
,那么你不必担心块被返回为string
。
当你有一个Buffer
块后,你可以根据自己的选择对其进行操作。为了全面起见,以下是如何在预设缓冲区大小的情况下使用它,并同时检查Content-Length
:
const BUFFER_SIZE = 4096;
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) {
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) {
}
});
req.on('end', () => {
if (data.length > bytesWritten) {
data = data.subarray(0, bytesWritten);
}
resolve(data);
});
req.on('error', (err) => {
reject(err);
});
});
}
选择在这里使用缓冲区大小是为了避免立即保留大量的内存,而只在需要时获取RAM。“Promise”功能只是为方便而添加的。