56

I'm trying to figure out how the best way to easily send HTTP/HTTPS requests and to handle gzip/deflate compressed responses along with cookies.

The best I found was https://github.com/mikeal/request which handles everything except compression. Is there a module or method that will do everything I ask?

If not, can I combine request and zlib in some manner? I tried to combine zlib and http.ServerRequest, and it failed miserably.

double-beep
  • 5,031
  • 17
  • 33
  • 41
wridgers
  • 717
  • 1
  • 5
  • 8
  • Possible duplicate of [How do I ungzip (decompress) a NodeJS request's module gzip response body?](http://stackoverflow.com/questions/12148948/how-do-i-ungzip-decompress-a-nodejs-requests-module-gzip-response-body) – Sindre Sorhus May 06 '17 at 10:41

6 Answers6

115

For anyone coming across this in recent times, the request library supports gzip decompression out of the box now. Use as follows:

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

From the github readme https://github.com/request/request

gzip - If true, add an Accept-Encoding header to request compressed content encodings from the server (if not already present) and decode supported content encodings in the response. Note: Automatic decoding of the response content is performed on the body data returned through request (both through the request stream and passed to the callback function) but is not performed on the response stream (available from the response event) which is the unmodified http.IncomingMessage object which may contain compressed data. See example below.

Ryan Knell
  • 6,204
  • 2
  • 40
  • 32
  • 1
    This is incorrect for version 2.53.0, see my answer. – Yuri Astrakhan May 28 '15 at 00:49
  • 1
    Works for me with 2.56.0 – makc May 30 '15 at 16:51
  • I have added the explanation from the github page. The example is taken directly from the documentation and should be working. Make sure you are using the third parameter in the callback (body) as the rest of the response is probably compressed – Ryan Knell May 31 '15 at 19:16
  • @RyanKnell can you please modify this as such? https://gist.github.com/niftylettuce/dffb449ab754e3de111788411c29f686 - note that I added `encoding: null` so that we can write to file locally –  Jul 27 '17 at 20:12
  • 1
    This is not working in the current version, as per https://stackoverflow.com/questions/50795520/meteor-http-client-api-call-gzip-uncompress-resultant-json-not-working – Rhys Stephens Jun 13 '18 at 07:25
  • Best answer, for sure. – Codebeat Aug 25 '18 at 02:20
  • oddly, the gzip option is not documented in the @types/node declaration file for https – Mattias Martens Mar 14 '22 at 22:41
  • oh, no, it is where it should be: in the request library. no such option appears to exist for using https.request, rather than request.default. – Mattias Martens Mar 14 '22 at 22:58
84

Note: as of 2019, request has gzip decompression built in. You can still decompress requests manually using the below method.

You can simply combine request and zlib with streams.

Here is an example assuming you have a server listening on port 8000 :

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

var headers = {
    'Accept-Encoding': 'gzip'
};

request({url:'http://localhost:8000/', 'headers': headers})
    .pipe(zlib.createGunzip()) // unzip
    .pipe(process.stdout); // do whatever you want with the stream
Kevin Burke
  • 61,194
  • 76
  • 188
  • 305
jcreignou
  • 3,670
  • 1
  • 23
  • 21
  • 1
    Is there a way to differentiate between responses that are gzipped, deflated or otherwise compressed or not compressed. Because the webserver may not return compressed responses and not respect the header. – CMCDragonkai Mar 03 '14 at 16:04
  • @CMCDragonkai I have edited the answer to make decoding conditional. – Ruben Verborgh Mar 04 '14 at 15:06
  • @RubenVerborgh what answer are you referring to? – CMCDragonkai Mar 04 '14 at 15:38
  • @CMCDragonkai The above answer by jcreignou. Seems like my edits haven't gone through yet. – Ruben Verborgh Mar 05 '14 at 10:07
  • Can gzipped and deflated responses be both decoded by the zlib library? – CMCDragonkai Mar 05 '14 at 11:41
  • @CMCDragonkai The code is on this gist as well: https://gist.github.com/RubenVerborgh/9372495 You can decode deflated using `zlib.createDeflate`, or even `zlib.createUnzip` if you're not sure what compression algorithm was used. – Ruben Verborgh Mar 05 '14 at 17:49
  • Note from the `request` readme : Automatic decoding of the response content is performed on the body data returned through `request` (both through the `request` stream and passed to the callback function) but is not performed on the `response` stream (available from the response event) which is the unmodified. – Souf Jan 15 '19 at 14:35
10

Here's a working example that gunzips the response

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

Full code: https://gist.github.com/0xPr0xy/5002984

user764155
  • 231
  • 3
  • 5
6

Check out the examples at http://nodejs.org/docs/v0.6.0/api/zlib.html#examples

zlib is now built into node.

Dick Hardt
  • 441
  • 3
  • 7
  • Hmm those examples were not sufficient for me to be able to figure out how to use node.js with require and zlib on the Stack Exchange v2 API. – hippietrail Jan 28 '13 at 10:15
3

Looking inside the source code - you must set the gzip param on the request lib itself for gzip to work. Not sure if this was intentional or not, but this is the current implementation. No extra headers are needed.

var request = require('request');
request.gzip = true;
request({url: 'https://...'},  // use encoding:null for buffer instead of UTF8
    function(error, response, body) { ... }
);
Yuri Astrakhan
  • 8,808
  • 6
  • 63
  • 97
  • This is very strange - in IDEA, option's gzip:true is not applied to the self, but when running without debugging, {gzip:true} also works. Might need to investigate further. – Yuri Astrakhan May 28 '15 at 09:23
  • how to use it in express and check whether gzip or compression is applied or not ! – Rizwan Patel Jun 08 '17 at 10:18
3

All the answers here did not work and I was getting raw bytes back instead and the gzip flag was not working either. As it turns out you need to set the encoding to null to prevent requests from transforming the response to utf-8 encoding and instead keeps the binary response.

const request = require("request-promise-native");
const zlib = require("zlib");

const url = getURL("index.txt");
const dataByteBuffer = await request(url, { encoding: null });
const dataString = zlib.gunzipSync(response);