首先,我尝试了在网络上任何地方可以找到的所有方法,包括 SO 相关问题的答案,但无法使任何工作发挥作用。这就是为什么我要问一个新问题。
我在 envoy 上使用 Lua 过滤器将标头和正文块发送到一个简单的节点应用程序,该应用程序仅将它们写入文件。在节点应用程序中,我接收标头和正文块以及 http 事务索引以及它们是否属于请求或响应,因此能够完整地重建请求和响应。
有时,我会收到从 gzip 压缩的 Lua 过滤器发送的响应。无论我如何尝试使用节点的 zlib 库,在尝试解压缩它时总是遇到相同的错误。
例如,这些是响应内容(正文被截断并删除了不相关的标头):
content-encoding: gzip
content-type: application/json
transfer-encoding: chunked
�ėmo ...
当我在正文开始之前删除标题和换行符时,我知道我在编写文件时添加了自己,并尝试使用以下命令解压缩剩余部分:
let compressed = fs.readFileSync(...);
zlib.gunzip(compressed, function(err, uncompressed) {
console.log(uncompressed);
if (err) {
console.log("Error: " + err.message);
}
});
我总是收到此错误:
错误:标头检查不正确
我用这样的代码得到了同样的错误:
var buffer = [];
gunzip.on('data', function(data) {
buffer.push(data.toString())
}).on("end", function() {
console.log(buffer.join(""));
}).on("error", function(e) {
console.log("Error: " + e.message);
})
let compressed = fs.readFileSync(...);
gunzip.write(compressed);
如果我用
tcpdump
捕获相同的请求,我可以看到我在tcp流中得到的内容和从Lua过滤器发送到节点的数据中的内容是相似的。但是,如果我在wireshark中加载tcp转储,当我要求它遵循http流时,它会正确解压缩数据,所以我知道数据是有效的,并且有一种方法可以解压缩它。
使用在节点上运行的 JavaScript 解压缩 gzip 压缩的 http 正文中的块的正确方法是什么?
长话短说,PEBCAK - 有点。
当您通过http发送二进制数据并在节点中接收它时,必须小心地将其始终作为二进制处理。任何到字符串的转换都有修改数据的风险 - 这正是我所发生的事情。
从 http 请求接收二进制数据的正确方法如下:
let data = [];
request.on("data", chunk => {
data.push(chunk);
});
request.on("end", chunk => {
if (chunk) {
data.push(chunk);
}
allData = Buffer.concat(data);
doSomethingWithTheBinaryData(allData);
}
我在做什么:
let data = "";
request.on("data", chunk => {
data += chunk.toString();
});
request.on("end", chunk => {
if (chunk) {
data += chunk.toString();
}
doSomethingWithTheBinaryData(data);
}
当接收 gzip 编码的数据时,第二个变体会损坏 gzip header。一旦我切换到累积数据的正确变体,使用
zlib.gunzipSync()
就能够解压缩 gzip 有效负载。