在Nodejs或者express的response中设置 'content-encoding': 'gzip'

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liangxw1/article/details/84790148

环境: Nodejs/express + Apache

如题,如果在后端的express server中,需要读取server上的大文件或者需要返回的数据为比较大的对象时(比如几十M的数据时),考虑用stream/pipe的方式处理data,流方式提供一些实用的高效的工具来处理比较大的data的处理,之后可以直接输出给response; 但是需要了解的是,最好是以压缩比如gzip或者deflate的方式返回给浏览器

或者请求的所有数据统统以压缩的形式返回给浏览器,所以最主要的前提是,根据用户的浏览器判断,当前这个client端的browser的请求是支持哪种类型的解压缩,比如gzip或者是deflate等,这里压缩的倍率大概为,压缩前: 50M左右, 压缩后3M左右,基本会有10倍多的压缩率,所以在网络间传输时性能会有很大提升.

这里的例子是用nodejs的,我理解用其他的语言比如java,道理也是一样的,语言只是封装和实现了tcp,http协议,优化的最后都是要了解到这些。

>>为什么要压缩,这里讲的很清楚 --> https://blog.csdn.net/liangxw1/article/details/84835199

// 用stream/pipe的方式返回data在response里,需要在http的response header中的 Accept-Encoding: gzip或者deflate,可以做到在server端压缩,在browser client端解压缩data并显示. 代码如下

module.exports.getTest = function (req, res) {
    // A
    // filepath, 这里filepath路径对应的文件为 *.json.gz的类型
    // 注,这里因为已经把json数据压缩成*.json.gz了,所以直接用stream/pipe读到response返回即可,
    // 因为浏览器自己可以解析(解压缩)*.json.gz文件为json数据
    // 
    // 这里我认为是这样的: 当需要处理读取大文件或者比较大的数据时,用正常的res.json(data)返回数据,这可能会有性能问题,
    //   但是用stream/pipe这种流的方式处理大文件或者数据时,是有优势的,可以提高处理性能,
    //   但是,这种流的方式放到response后,只用如下 Apache的配置并没有起到gzip或者deflate的压缩效果,也许需要如下设置??还不确定,***有时间在本机测试一下***
    //    AddOutputFilterByType DEFLATE application/octet-stream??
    //    所以这里就 显示的 用如下的res.writeHead的方式手动设置content-encoding,即可让这里压缩的*.json.gz传输给浏览器并解压缩,的节省带宽,提高性能的效果
    fs.exists(filepath, function (exists) {
        if (exists === true) {

            const srcReadStream = fs.createReadStream(filepath);

            // Success with response body
            // res.status(200);
            // 注,这里只是例子代码,这里应该根据用户的浏览器所支持的解压缩类型是gzip还是deflate来设置content-encoding
            res.writeHead(200, { 'content-encoding': 'gzip' });
            srcReadStream.pipe(res);
            
            srcReadStream.on('close', function () {
                // It can go here after close event
                srcReadStream.destroy();
            });
            
            srcReadStream.on('error', function (err) {
                srcReadStream.destroy();
            });
        } else {

            ...
        }
    });
}

查看相关资料,让数据在返回的response中以压缩的形式返回,至少可以在如下两个地方做:

  1. 在应用程序的代码中,判断请求的http header中的 Accept-Encoding: gzip, deflate 支持什么类型的压缩和解压缩,之后在返回的response中设置Content-Encoding: gzip或者deflate等

         在nodejs/express中,compression这个插件可以做到压缩后在传输给client browser. 之后browser可以正确解压缩并显示

         但是这种方式,个人不是很推荐,因为对nodejs来说大量的处理压缩的动作可能会影响性能(??),另外如果可以在Apache服务器上做,应该会更好,首先对nodejs的压力小,代码不用改,侵入性小,在Apache上配置也相对灵活

    2. 在Apache服务器上,启用如下配置

https://httpd.apache.org/docs/2.4/mod/mod_deflate.html

https://varvy.com/pagespeed/enable-compression.html

LoadModule deflate_module modules/mod_deflate.so

// 下面的各项需要压缩什么类型的数据就打开相应的行
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html text/plain text/xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml

// 下面的配置,暂时不理解,待深入调查??
DeflateFilterNote Input instream
DeflateFilterNote Output outstream
DeflateFilterNote Ratio ratio

如果不用stream/pipe的方式返回data在response,而是用expess的res.json(data), 用上面的#1,#2两种方式都可以做到客户端和server端压缩数据在传输和解压缩的效果.

下面这种方式的stream/pipe方式是可以的,这个类似于上面第一种方式

// 参考: https://stackoverflow.com/questions/3894794/node-js-gzip-compression

// server example
// Running a gzip operation on every request is quite expensive.
// It would be much more efficient to cache the compressed buffer.
var zlib = require('zlib');
var http = require('http');
var fs = require('fs');
http.createServer(function(request, response) {
  var raw = fs.createReadStream('sample-drag.html');
  var acceptEncoding = request.headers['accept-encoding'];
  if (!acceptEncoding) {
    acceptEncoding = '';
  }

  // Note: this is not a conformant accept-encoding parser.
  // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
  if (acceptEncoding.match(/\bgzip\b/)) {
    response.writeHead(200, { 'content-encoding': 'gzip' });
    raw.pipe(zlib.createGzip()).pipe(response);
  } else if (acceptEncoding.match(/\bdeflate\b/)) {
    response.writeHead(200, { 'content-encoding': 'deflate' });
    raw.pipe(zlib.createDeflate()).pipe(response);
  } else {
    response.writeHead(200, {});
    raw.pipe(response);
  }
}).listen(1337);


// 另一个例子
exports.helloWorld = function helloWorld(req, res) {
  const zlib = require('zlib');

  // Obtain JSON stream from your source...

  res.status(200);

  res.set('Content-Type', 'text/plain');
  res.set('Content-Encoding', 'gzip');

  json.pipe(zlib.createGzip()).pipe(res);
};

猜你喜欢

转载自blog.csdn.net/liangxw1/article/details/84790148
今日推荐