我如何ungzip(解压缩)NodeJS请求的模块gzip响应体?

时间:2012-08-27 20:15:12

标签: javascript node.js express zlib

如何在请求的模块响应中解压缩gzipped主体?

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

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;
                    }
                });
            }
        }
    }
}

10 个答案:

答案 0 :(得分:48)

我也无法获得请求,所以最终使用了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);
});

答案 1 :(得分:34)

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

答案 2 :(得分:25)

就像@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);
    }
});

答案 3 :(得分:23)

实际上,请求模块处理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解析。让我解释一下。如果您希望请求模块自动解析正文并在body参数中提供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

答案 4 :(得分:4)

在尝试了不同的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
    }
  }

});

答案 5 :(得分:4)

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

截至2017年12月,请求和请求承诺都处理开箱即用:

var list = ["company1", "company2", "company3", "company4", "company5", "company6"];
var wrapper = $('.wrapper');
var row = {};
$.each(list,function(key,val){
    if((key % 3) == 0){
        row = $('<div>', {'class' : 'row'});
        wrapper.append(row);
    }
    var col = $('<div>', {'class' : 'col col-4'});
    col.text(val);
    row.append(col);
});

答案 6 :(得分:3)

这是一个工作示例(使用节点的请求模块)来压制响应

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

答案 7 :(得分:3)

这是我的两分钱。我遇到了同样的问题,发现了一个名为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());
  }));

答案 8 :(得分:1)

使用gotrequest替代方案,您只需执行以下操作:

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

需要时自动处理解压缩。

答案 9 :(得分:1)

我正在使用节点获取。我得到了 function markoffagency_attributes_shortcode( $atts ) { global $product; if( ! is_object( $product ) || ! $product->has_attributes() ){ return; } // parse the shortcode attributes $args = shortcode_atts( array( 'attributes' => array_keys( $product->get_attributes() ), // by default show all attributes ), $atts ); // is pass an attributes param, turn into array if( is_string( $args['attributes'] ) ){ $args['attributes'] = array_map( 'trim', explode( '|' , $args['attributes'] ) ); } // start with a null string because shortcodes need to return not echo a value $html = ''; if( ! empty( $args['attributes'] ) ){ foreach ( $args['attributes'] as $attribute ) { // get the WC-standard attribute taxonomy name // $taxonomy = strpos( $attribute, 'pa_' ) === false ? wc_attribute_taxonomy_name( $attribute ) : $attribute; $taxonomy = strpos( $attribute, 'pa_' ) === false ? wc_attribute_taxonomy_name( $attribute ) : $attribute; if( taxonomy_is_product_attribute( $taxonomy ) ){ // this is my field $terms = get_the_terms( $product->ID, $taxonomy ); $thumbnail = get_field('image_atr' . $terms); $value .= '<img class="taxonomy-image" src="'. $thumbnail .'" />'; // Get the attribute label. $attribute_label = wc_attribute_label( $taxonomy ); // Build the html string with the label followed by a clickable list of terms. // Updated for WC3.0 to use getters instead of directly accessing property. $html .= get_the_term_list( $product->get_id(), $taxonomy, '<div class="feature-individual-item"><div class="quadro width_imgs ' . $attribute_label . '"></div>' . $value . '', ', ', '</div>' ); } } // if we have anything to display, wrap it in a <ul> for proper markup // OR: delete these lines if you only wish to return the <li> elements if( $html ){ $html = '<div class="feature-individual">' . $html . '</div>'; } } return $html; } add_shortcode( 'display_attributes', 'markoffagency_attributes_shortcode' ); ,我真正想要的是 response.body