【问题标题】:How do I ungzip (decompress) a NodeJS request's module gzip response body?如何解压缩(解压缩)NodeJS 请求的模块 gzip 响应正文?
【发布时间】:2012-08-22 08:27:23
【问题描述】:

如何在请求的模块响应中解压缩压缩后的正文?

我在网上尝试了几个例子,但似乎都没有。

request(url, function(err, response, body) {
    if(err) {
        handleError(err)
    } else {
        if(response.headers['content-encoding'] == 'gzip') {    
            // How can I unzip the gzipped string body variable?
            // For instance, this url:
            // http://highsnobiety.com/2012/08/25/norse-projects-fall-2012-lookbook/
            // Throws error:
            // { [Error: incorrect header check] errno: -3, code: 'Z_DATA_ERROR' }
            // Yet, browser displays page fine and debugger shows its gzipped
            // And unzipped by browser fine...
            if(response.headers['content-encoding'] && response.headers['content-encoding'].toLowerCase().indexOf('gzip') > -1) {   
                var body = response.body;                    
                zlib.gunzip(response.body, function(error, data) {
                    if(!error) {
                        response.body = data.toString();
                    } else {
                        console.log('Error unzipping:');
                        console.log(error);
                        response.body = body;
                    }
                });
            }
        }
    }
}

【问题讨论】:

  • 浏览器不应该透明地这样做吗?
  • 我添加了 node.js 标记,但我明白这并不清楚...让我编辑帖子...
  • 您可以将数据保存到文件req.gz 并从命令行解压缩吗?如果是,gunzip req.gzfile req.gz 的输出是什么
  • 你好安德鲁!谢谢你的建议。如果我将文件保存到“req.gz”文件,在桌面上提取它会生成一个名为“req.gz.cpgz”的文件。依次提取此文件会生成名为“req 2.gz”的第三个文件。请求正文在读取正文之前被编码为 utf8 (response.setEncoding('utf8'))。但是,它似乎没有什么不同。我得到同样的错误和类似的桌面文件结果。
  • request 3.0 将在 node v0.10 发布后自动支持此功能

标签: javascript node.js express zlib


【解决方案1】:

我也无法获得工作请求,所以最终改用 http。

var http = require("http"),
    zlib = require("zlib");

function getGzipped(url, callback) {
    // buffer to store the streamed decompression
    var buffer = [];

    http.get(url, function(res) {
        // pipe the response into the gunzip to decompress
        var gunzip = zlib.createGunzip();            
        res.pipe(gunzip);

        gunzip.on('data', function(data) {
            // decompression chunk ready, add it to the buffer
            buffer.push(data.toString())

        }).on("end", function() {
            // response and decompression complete, join the buffer and return
            callback(null, buffer.join("")); 

        }).on("error", function(e) {
            callback(e);
        })
    }).on('error', function(e) {
        callback(e)
    });
}

getGzipped(url, function(err, data) {
   console.log(data);
});

【讨论】:

  • 终于!我一直在设置标头以接受 gzip 并尝试代理和所有类型的东西,但这确实是使用 stackoverflow API 的诀窍!一件小事:var gunzip = gzip.createGunzip(); 应该是 var gunzip = zlib.createGunzip();
  • 我尝试使用所有请求方法但失败了。这个有效!
  • 这行得通,但是通过在请求模块上设置几个选项,有一种更好、更简单的方法来做到这一点。请在下面阅读我的回答。
【解决方案2】:

尝试将encoding: null 添加到您传递给request 的选项中,这将避免将下载的正文转换为字符串并将其保存在二进制缓冲区中。

【讨论】:

  • 我遇到了同样的问题,这个编码选项对我有用。谢谢!!
【解决方案3】:

就像@Iftah 说的,设置encoding: null

完整示例(更少的错误处理):

request = require('request');
zlib = require('zlib');

request(url, {encoding: null}, function(err, response, body){
    if(response.headers['content-encoding'] == 'gzip'){
        zlib.gunzip(body, function(err, dezipped) {
            callback(dezipped.toString());
        });
    } else {
        callback(body);
    }
});

【讨论】:

    【解决方案4】:

    实际上是请求模块处理 gzip 响应。为了告诉请求模块解码回调函数中的 body 参数,我们必须在选项中将“gzip”设置为 true。让我用一个例子来解释你。

    示例:

    var opts = {
      uri: 'some uri which return gzip data',
      gzip: true
    }
    
    request(opts, function (err, res, body) {
     // now body and res.body both will contain decoded content.
    })
    

    注意:您在“响应”事件中获得的数据未解码。

    这对我有用。希望它也适用于你们。

    我们在使用请求模块时经常遇到的类似问题是 JSON 解析。让我解释一下。如果您希望请求模块自动解析正文并在正文参数中为您提供 JSON 内容。然后你必须在选项中将 'json' 设置为 true。

    var opts = {
      uri:'some uri that provides json data', 
      json: true
    } 
    request(opts, function (err, res, body) {
    // body and res.body will contain json content
    })
    

    参考:https://www.npmjs.com/package/request#requestoptions-callback

    【讨论】:

    • 谢谢你!它有效,我不知道 request-promise 有一个 gzip 标志。
    • 设置"gzip": true 选项的一个注意事项...服务器响应必须包含"Content-Encoding": "gzip",以便请求模块实际解压缩响应。我一直在处理一个没有正确设置“Content-Encoding”标头的服务器,直到我阅读了请求模块的源代码,我才发现这是必需的。希望此评论能帮助其他人节省时间,在您遇到类似情况时尝试弄清楚为什么这不起作用。
    【解决方案5】:

    https://gist.github.com/miguelmota/9946206中所见:

    截至 2017 年 12 月,request 和 request-promise 都开箱即用地处理它:

    var request = require('request')
      request(
        { method: 'GET'
        , uri: 'http://www.google.com'
        , gzip: true
        }
      , function (error, response, body) {
          // body is the decompressed response body
          console.log('server encoded the data as: ' + (response.headers['content-encoding'] || 'identity'))
          console.log('the decoded data is: ' + body)
        }
      )
    

    【讨论】:

      【解决方案6】:

      在尝试了不同的 gunzip 方法并解决了与编码有关的错误后,我制定了更多 complete answer

      希望这对你也有帮助:

      var request = require('request');
      var zlib = require('zlib');
      
      var options = {
        url: 'http://some.endpoint.com/api/',
        headers: {
          'X-some-headers'  : 'Some headers',
          'Accept-Encoding' : 'gzip, deflate',
        },
        encoding: null
      };
      
      request.get(options, function (error, response, body) {
      
        if (!error && response.statusCode == 200) {
          // If response is gzip, unzip first
          var encoding = response.headers['content-encoding']
          if (encoding && encoding.indexOf('gzip') >= 0) {
            zlib.gunzip(body, function(err, dezipped) {
              var json_string = dezipped.toString('utf-8');
              var json = JSON.parse(json_string);
              // Process the json..
            });
          } else {
            // Response is not gzipped
          }
        }
      
      });
      

      【讨论】:

        【解决方案7】:

        这是我的两分钱。我遇到了同样的问题,发现了一个很酷的库,叫做concat-stream

        let request = require('request');
        const zlib = require('zlib');
        const concat = require('concat-stream');
        
        request(url)
          .pipe(zlib.createGunzip())
          .pipe(concat(stringBuffer => {
            console.log(stringBuffer.toString());
          }));
        

        【讨论】:

        • 当远程文件实际上是预压缩的 .gz 文件时,这是唯一对我有用的方法。
        【解决方案8】:

        这是一个对响应进行压缩的工作示例(使用 node 的请求模块)

        function gunzipJSON(response){
        
            var gunzip = zlib.createGunzip();
            var json = "";
        
            gunzip.on('data', function(data){
                json += data.toString();
            });
        
            gunzip.on('end', function(){
                parseJSON(json);
            });
        
            response.pipe(gunzip);
        }
        

        完整代码:https://gist.github.com/0xPr0xy/5002984

        【讨论】:

        • 非常感谢。我遇到了问题并使用了您的解决方案,效果很好。
        【解决方案9】:

        使用gotrequest 替代方案,您可以这样做:

        got(url).then(response => {
            console.log(response.body);
        });
        

        在需要时自动处理解压缩。

        【讨论】:

          【解决方案10】:

          我正在使用节点获取。我得到了response.body,我真正想要的是await response.text()

          【讨论】:

          • 就我而言,我使用的是response.json(),所以出现了一些错误,但在使用response.text() 之后它起作用了。非常感谢:)
          猜你喜欢
          • 2012-02-12
          • 2012-12-02
          • 2021-04-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多