Node.js代理,处理gzip解压缩

3

我目前正在开发一个代理服务器,我们需要修改通过它传输的数据(使用正则表达式)。

在大多数情况下,它都能正常工作,但对于使用gzip作为内容编码的网站(我想),我遇到了一个叫做compress的模块,并尝试将接收到的块通过解压缩/ gunzip流进行处理,但结果并不如我所预期。(有关代码,请参见下文)

我想发一些支持我的问题的代码,这是使用mvc(express)加载的代理:

module.exports = {
index: function(request, response){
    var iframe_url = "www.nu.nl"; // site with gzip encoding    

    var http = require('http');     
    var httpClient = http.createClient(80, iframe_url);
    var headers = request.headers;
    headers.host = iframe_url;

    var remoteRequest = httpClient.request(request.method, request.url, headers);

    request.on('data', function(chunk) {
        remoteRequest.write(chunk);
    });

    request.on('end', function() {
        remoteRequest.end();
    });

    remoteRequest.on('response', function (remoteResponse){         
        var body_regexp = new RegExp("<head>"); // regex to find first head tag
        var href_regexp = new RegExp('\<a href="(.*)"', 'g'); // regex to find hrefs

        response.writeHead(remoteResponse.statusCode, remoteResponse.headers);

        remoteResponse.on('data', function (chunk) {
    var body = doDecompress(new compress.GunzipStream(), chunk);
            body = body.replace(body_regexp, "<head><base href=\"http://"+ iframe_url +"/\">");
            body = body.replace(href_regexp, '<a href="#" onclick="javascript:return false;"');             

            response.write(body, 'binary');
        });

        remoteResponse.on('end', function() {

            response.end();
            });
        });
    }
};

在var body部分,我希望读取内容,并在这种情况下通过将所有href替换为#来删除它们。当我们遇到被gzip编码/压缩的网站时,问题就出现了,因为它变成了无法识别的乱码,我们无法应用正则表达式。
现在我已经尝试使用node-compress模块进行操作:
 doDecompress(new compress.GunzipStream(), chunk);

这指的是

function doDecompress(decompressor, input) {
  var d1 = input.substr(0, 25);
  var d2 = input.substr(25);

  sys.puts('Making decompression requests...');
  var output = '';
  decompressor.setInputEncoding('binary');
  decompressor.setEncoding('utf8');
  decompressor.addListener('data', function(data) {
    output += data;
  }).addListener('error', function(err) {
    throw err;
  }).addListener('end', function() {
    sys.puts('Decompressed length: ' + output.length);
    sys.puts('Raw data: ' + output);
  });
  decompressor.write(d1);
  decompressor.write(d2);
  decompressor.close();
  sys.puts('Requests done.');
}

但是由于块输入是一个对象,所以它失败了,因此我尝试将其作为chunk.toString()提供,但是它也因为无效的输入数据而失败。
我想知道我是否朝着正确的方向前进?
1个回答

4
解压器期望以二进制编码的输入。您的响应接收到的块是 Buffer 的一个实例,toString() 方法默认返回一个 UTF-8 编码的字符串。因此,您需要使用 chunk.toString('binary') 来使其正常工作,这也可以在 演示 中看到。

谢谢回复,但是当我将它改为:var body = doDecompress(new compress.GunzipStream(), chunk.toString('binary'));时,它仍然在doDecompress函数的第17行抛出错误,显示“输入数据已损坏”。 - M0rph3v5
你的输入是否分块编码?如果没有,那么在解压缩之前需要缓冲完整的主体。因此,你需要将 chunks.toString('binary') 添加在一起,并在 end 回调中调用解压缩器。 - Ivo Wetzel
谢谢,看起来确实是那个问题,我必须将它们加入一个变量中,并在最后进行解压缩。现在似乎我可以做我想做的事情了,非常感谢! - M0rph3v5
我现在遇到的唯一问题就是,当我将输出输出到控制台时,确实会得到完整的HTML,但由于某种原因,在响应中写入它时只显示一半的站点。在decompresser的“end”回调函数中执行 -> proxysponse.end(output); - M0rph3v5
node -v 返回 v0.2.5,同时我指的是浏览器中只显示了网站的一半。 - M0rph3v5
显示剩余4条评论

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