NodeJs使用zlib压缩与解压缩处理含API,gzip/deflate压缩详解

为了减少网络传输数据量,http传输过程中会采用通用的压缩算法来压缩数据,gzip属于最常用的压缩算法。

使用node的http模块发送请求时并没有帮我们进行解压,因此我们需要手动去判断gzip。

var http = require('http');
var options = {
 hostname: 'www.qq.com',
 port: 80,
 method: 'get',
 headers: {
  'Accept-Encoding': 'gzip'
 }
}

http.request(options, handler);

function handler(responder) {
 // do something
}

我们设置http头Accept-Encoding为gzip告诉服务器我们支持gzip压缩,服务器收到请求后,返回responder头中content-encoding带有gzip表明返回的数据为gzip压缩过的内容,node中可以通过responder.headers[‘content-encoding’]来判断服务器返回内容是否gzip压缩过。

function handler(responder) {
 if(responder.headers['content-encoding'].indexOf('gzip') != -1) {
  // 解压gzip
 }
}

已经可以判断服务器返回的是gzip压缩过的内容,接下来我们需要去解压,幸好node提供了zlib模块。

zlib模块提供通过 Gzip 和 Deflate/Inflate 实现的压缩功能,可以通过这样使用它

const zlib = require('zlib');

压缩或者解压数据流(例如一个文件)通过zlib流将源数据流传输到目标流中来完成。

const gzip = zlib.createGzip();
const fs = require('fs');
const inp = fs.createReadStream('input.txt');
const out = fs.createWriteStream('input.txt.gz');

inp.pipe(gzip).pipe(out);

数据的压缩或解压缩也可以只用一个步骤完成:

const input = '.................................';
zlib.deflate(input, (err, buffer) => {
  if (!err) {
    console.log(buffer.toString('base64'));
  } else {
    // handle error
  }
});

const buffer = Buffer.from('eJzT0yMAAGTvBe8=', 'base64');
zlib.unzip(buffer, (err, buffer) => {
  if (!err) {
    console.log(buffer.toString());
  } else {
    // handle error
  }
});

在压缩流上调用 .flush() 方法将使 zlib 返回尽可能多的输出. 这可能是以压缩质量下降 为代价的,但是当需要尽快提供数据时,这可能是有用的

在以下的实例中, flush() 方法用于将部分压缩过的 HTTP 响应返回给客户端:

const zlib = require('zlib');
const http = require('http');

http.createServer((request, response) => {
  // For the sake of simplicity, the Accept-Encoding checks are omitted.
  response.writeHead(200, { 'content-encoding': 'gzip' });
  const output = zlib.createGzip();
  output.pipe(response);

  setInterval(() => {
    output.write(`The current time is ${Date()}\n`, () => {
      // The data has been passed to zlib, but the compression algorithm may
      // have decided to buffer the data for more efficient compression.
      // Calling .flush() will make the data available as soon as the client
      // is ready to receive it.
      output.flush();
    });
  }, 1000);
}).listen(1337);

~~~

1. 压缩与解压缩处理 #

可以使用zlib模块进行压缩及解压缩处理,压缩文件以后可以减少体积,加快传输速度和节约带宽
代码

2. 压缩对象 #

压缩和解压缩对象都是一个可读可写流

方法 说明
zlib.createGzip 返回Gzip流对象,使用Gzip算法对数据进行压缩处理
zlib.createGunzip 返回Gzip流对象,使用Gzip算法对压缩的数据进行解压缩处理
zlib.createDeflate 返回Deflate流对象,使用Deflate算法对数据进行压缩处理
zlib.createInflate 返回Deflate流对象,使用Deflate算法对数据进行解压缩处理

3. 压缩和解压缩 #

var zlib = require('zlib');
var fs = require('fs');

function zip(src) {
    var gzip = zlib.createGzip();//创建压缩流
    var inputStream = fs.createReadStream(src);
    var outputStream = fs.createWriteStream(src+'.gz');
    inputStream.pipe(gzip).pipe(outputStream);
}
zip('source.txt');

function gunzip(src){
    var gunzip = zlib.createGunzip();
    var inputStream = fs.createReadStream(src);
    var outputStream = fs.createWriteStream(src.slice(0,-3));
    inputStream.pipe(gunzip).pipe(outputStream);
}


gunzip('source.txt.gz');

4. 在http中的应用 #

var zlib = require('zlib');
var fs = require('fs');
var http = require('http');
http.createServer(function (request, response) {
    var raw = fs.createReadStream('.' + request.url);
    var acceptEncoding = request.headers['accept-encoding'];
    if (!acceptEncoding) {
        acceptEncoding = '';
    }
    if (acceptEncoding.match(/\bdeflate\b/)) {
        response.setHeader('Content-Encoding','deflate');
        raw.pipe(zlib.createDeflate()).pipe(response);
    } else if (acceptEncoding.match(/\bgzip\b/)) {
        response.setHeader('Content-Encoding','gzip');
        raw.pipe(zlib.createGzip()).pipe(response);
    } else {
        raw.pipe(response);
    }
}).listen(9090)
var zlib = require('zlib');
var fs = require('fs');
var http = require('http');

var request = http.get({
    host: 'localhost',
    path: '/index.html',
    port: 9090,
    headers: {
        'accept-encoding': 'gzip,deflate'
    }
})

request.on('response', function (response) {
    var output = fs.createWriteStream('test.txt');
    switch (response.headers['content-encoding']) {
        case 'gzip':
            response.pipe(zlib.createGunzip()).pipe(output);
            break;
        case 'deflate':
            response.pipe(zlib.createInflate()).pipe(output);
            break;
        default:
            response.pipe(output);
            break;
    }
});
request.end();

5. 方法调用 #

var zlib = require('zlib');
var fs = require('fs');

var out = fs.createWriteStream('input.log');
var input = 'input';
zlib.gzip(input, function (err, buffer) {
    if (!err) {
        zlib.unzip(buffer, function (err, buffer) {
            if (!err) {
                console.log(buffer.toString());
                out.end(buffer);
            }
        })
    }
})

~

扩展:

我们用zlib模块来解压gzip

var zlib = require('zlib');
var fs = require('fs');
var gunzipStream = zlib.createGunzip();
var toWrite = fs.createWriteStream('qq.html');

zlib.createGunzip是一个transform流,通过pipe我们可以很方便解压gzip

function handler(responder) {
 if(responder.headers['content-encoding'].indexOf('gzip') != -1) {
  responder.pipe(gunzipStream).pipe(toWrite);
 }
}

若是要让服务端支持gzip压缩可以先判断请求头的accept-encoding是否含有gzip

var fs = require('fs');
var http = require('http');
var zlib = require('zlib');

http.createServer(function(req, res) {
 var file = fs.createReadStream('./qq.html');
 var acceptEncoding = req.headers['accept-encoding'];
 if(acceptEncoding && acceptEncoding.indexOf('gzip') != -1) {
  var gzipStream = zlib.createGzip();
  // 设置返回头content-encoding为gzip
  res.writeHead(200, {
   "content-encoding": "gzip"
  });
  file.pipe(gzipStream).pipe(res);
 } else {
  res.writeHead(200);
  // 不压缩
  file.pipe(res);
 }
}).listen(8080);

使用curl测试一下

# 不带有Accept-Encoding:gzip 返回正常文本
curl localhost:8080
# 带Accept-Encoding:gzip 返回压缩过的文件
curl -H "Accept-Encoding:gzip" localhost:8080

通过zlib可以实现客户端和服务端对gzip的压缩和解压

在express中提供了compress的中间件用来处理gzip

~~

未经允许不得转载:WEB前端开发 » NodeJs使用zlib压缩与解压缩处理含API,gzip/deflate压缩详解

赞 (0)