Comment décompresser (décompresser) le corps de réponse gzip du module D'une requête NodeJS?

Comment décompresser un corps gzippé dans la réponse du module d'une requête?

J'ai essayé plusieurs exemples sur le web mais aucun d'entre eux ne semble fonctionner.

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;
                    }
                });
            }
        }
    }
}
53
demandé sur Alexis Tyler 2012-08-28 00:15:11

9 réponses

Je n'ai pas pu faire fonctionner la requête non plus, donc j'ai fini par Utiliser http à la place.

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);
});
42
répondu WearyMonkey 2013-05-09 00:33:51

Essayez d'Ajouter encoding: null aux options que vous passez à request, cela évitera de convertir le corps téléchargé en chaîne et de le conserver dans un tampon binaire.

34
répondu Iftah 2012-10-11 13:20:30

Comme @ Iftah a dit, set encoding: null.

Exemple complet (moins de gestion des erreurs):

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);
    }
});
22
répondu Andrew Homeyer 2014-02-24 17:59:36

En fait, le module request gère la réponse gzip. Afin de dire au module de requête de décoder l'argument body dans la fonction de rappel, nous devons définir le 'gzip' sur true dans les options. Permettez-moi de vous expliquer avec un exemple.

Exemple:

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

Remarque: Les données que vous obtenez sur l'événement' reponse ' ne sont pas décodées.

Cela fonctionne pour moi. J'espère que cela fonctionne pour vous aussi.

Le problème similaire que nous avons généralement rencontré en travaillant avec le module de requête est avec l'analyse JSON. Permettez-moi de l'expliquer. Si vous voulez que le module de requête analyse automatiquement le corps et vous fournisse du contenu JSON dans l'argument body. Ensuite, vous devez définir 'json' sur true dans les options.

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

Référence: https://www.npmjs.com/package/request#requestoptions-callback

21
répondu Sai Teja 2016-07-26 07:06:11

J'ai formulé une réponse plus complète Après avoir essayé les différentes façons de gunzip, et résolu les erreurs à faire avec l'encodage.

J'espère que cela vous aidera aussi:

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

});
4
répondu samwize 2014-05-28 02:42:44

Voici un exemple de travail (en utilisant le module de requête pour le nœud) qui gunzips la réponse

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

Code Complet: https://gist.github.com/0xPr0xy/5002984

3
répondu user764155 2013-02-21 07:58:22

Voici mes deux cents. J'ai eu le même problème et trouvé une belle bibliothèque appelée 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());
  }));
2
répondu Mark Robson 2016-04-11 14:29:53

Comme dans https://gist.github.com/miguelmota/9946206:

Request et request-promise le gèrent à partir de décembre 2017:

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)
    }
  )
2
répondu Francisco Carriedo Scher 2018-05-02 16:46:41

Avec got, un request alternative, vous pouvez tout simplement faire:

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

La décompression est gérée automatiquement en cas de besoin.

1
répondu Sindre Sorhus 2017-05-06 10:41:03