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