如何在 Nodejs 应用程序中解压缩 gzip 压缩的 http 主体?

问题描述 投票:0回答:1

首先,我尝试了在网络上任何地方可以找到的所有方法,包括 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 正文中的块的正确方法是什么?

node.js http zlib
1个回答
0
投票

长话短说,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 有效负载。

© www.soinside.com 2019 - 2024. All rights reserved.