web-dev-qa-db-fra.com

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

Comment décompresser un corps compressé dans la réponse de 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;
                    }
                });
            }
        }
    }
}
62
izk

Je ne pouvais pas obtenir de demande de travail non plus, donc 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);
});
51
WearyMonkey

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
Iftah

Comme @Iftah l'a dit, mettez encoding: null.

Exemple complet (moins de traitement 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);
    }
});
27
Andrew Homeyer

En fait, le module request gère la réponse gzip. Afin d'indiquer au module de requête de décoder l'argument body dans la fonction de rappel, nous devons définir le paramètre 'gzip' sur true dans les options. Laissez-moi 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 ça marche pour vous aussi.

Le problème similaire que nous rencontrons habituellement lorsque nous travaillons avec le module de requête concerne l'analyse JSON. Laissez-moi l'expliquer. Si vous voulez que le module de requête analyse automatiquement le corps et vous fournisse un 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

26
Sai Teja

Comme indiqué dans https://Gist.github.com/miguelmota/9946206 :

Request et request-promise traitent les problèmes dès 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)
    }
  )

J'ai formulé un plus réponse complète après avoir essayé les différentes méthodes de gunzip et résolu les erreurs de codage.

J'espère que ça va t'aider 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
samwize

Voici mes deux centimes. J'ai eu le même problème et j'ai trouvé une bonne 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());
  }));
3
Mark Robson

Voici un exemple de travail (en utilisant le module de requête pour le noeud) 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
user764155

Avec got , une alternative request, vous pouvez simplement faire:

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

La décompression est gérée automatiquement si nécessaire.

1
Sindre Sorhus