使用gzip/deflate压缩实现简单的HTTP请求

56

我正试图找出最简便的方法来发送HTTP/HTTPS请求并处理gzip/deflate压缩响应以及cookie。

我发现最好的方法是使用https://github.com/mikeal/request,它可以处理所有事情,除了压缩。是否有一个模块或方法可以满足我的所有需求?

如果没有,我能否将request和zlib结合起来呢?我尝试过将zlib和http.ServerRequest结合起来,但失败了。


可能是重复的问题,参考如何解压缩NodeJS请求模块gzip响应体? - Sindre Sorhus
6个回答

115

如果最近有人遇到这个问题,请求库现在已经原生支持 gzip 解压缩了。使用方式如下:

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

来自Github readme https://github.com/request/request

gzip - 如果为true,则向请求添加Accept-Encoding标头以从服务器请求压缩的内容编码(如果尚未存在),并在响应中解码支持的内容编码。注意:响应内容的自动解码是在request返回的数据体上执行的(通过请求流和传递给回调函数),但不会在响应流上执行(可从响应事件获取)该流是未修改的http.IncomingMessage对象,可能包含压缩数据。请参见下面的示例。


1
这对于版本2.53.0是不正确的,请看我的答案。 - Yuri Astrakhan
1
对于我来说,使用2.56.0可以正常工作。 - makc
我已经从Github页面添加了说明。这个例子直接从文档中获取,应该可以正常工作。确保在回调函数中使用第三个参数(body),因为响应的其余部分可能被压缩了。 - Ryan Knell
1
根据 https://dev59.com/Lazka4cB1Zd3GeqP2xKO,这在当前版本中无法工作。 - Rhys Stephens
哦,不,它应该在请求库中。似乎不存在使用https.request而不是request.default的选项。 - Mattias Martens
显示剩余3条评论

84

注意:截至2019年,请求(request)已内置gzip解压缩功能。您仍然可以使用以下方法手动解压缩请求。

您可以简单地将requestzlib与流(streams)结合使用。

这是一个示例,假设您有一个在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

1
有没有办法区分已经压缩过的响应是使用gzip、deflate或其他压缩方式,还是未经压缩。因为Web服务器可能不会返回压缩响应并且不遵守头文件。 - CMCDragonkai
@CMCDragonkai 我已经编辑了答案,使解码变成有条件的。 - Ruben Verborgh
@RubenVerborgh,您指的是哪个答案? - CMCDragonkai
@CMCDragonkai 上面的答案是由jcreignou提供的。看起来我的编辑还没有生效。 - Ruben Verborgh
zlib库能同时解码gzip和deflate压缩的响应吗? - CMCDragonkai
显示剩余2条评论

10
这是一个可行的示例,它可以对响应进行解压缩。
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


6

嗯,那些例子对我来说不足以让我弄清如何在Stack Exchange v2 API中使用node.js和require以及zlib。 - hippietrail

3

查看 源代码 可知:要启用 gzip,你必须在请求库本身上设置 gzip 参数。不确定这是否是有意为之,但这是当前的实现方式。无需额外的 headers。

var request = require('request');
request.gzip = true;
request({url: 'https://...'},  // use encoding:null for buffer instead of UTF8
    function(error, response, body) { ... }
);

这很奇怪 - 在IDEA中,选项的gzip:true不适用于自身,但在没有调试运行时,{gzip:true}也可以工作。可能需要进一步调查。 - Yuri Astrakhan
如何在Express中使用它,并检查是否应用了gzip或压缩! - Rizwan Patel

3
所有这里的回答都没有起作用,我只得到了原始字节,并且 gzip 标志也没有起作用。事实证明,您需要将编码设置为 null ,以防止请求将响应转换为 UTF-8 编码,而是保持二进制响应。
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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接