Zlib模块实现流压缩与解压

 2015年07月09日    2474     声明


在流传输过程中,为减少传输数据加快传输速度,往往会对流进行压缩。HTTP流就是如此,为提高网站响应速度,会在服务端进行压缩,客户端收到数据后再进行相应的解压。Node.js中的Zlib模块提供了流压缩与解压缩功能,Zlib模块提供了对 Gzip/GunzipDeflate/InflateDeflateRaw/InflateRaw类的绑定,这些类可以实现对可读流/可写流的压缩与解压。

  1. 关于gzip与deflate
  2. 使用Zlib模块创建类
  3. Zlib模块中的方法
  4. 使用示例


1. 关于gzip与deflate

deflate(RFC1951)是一种压缩算法,使用LZ77和哈弗曼进行编码。gzip(RFC1952)一种压缩格式,是对deflate的简单封装,gzip = gzip头(10字节) + deflate编码的实际内容 + gzip尾(8字节)。在HTTP传输中,gzip是一种常用的压缩算法,使用gzip压缩的HTTP数据流,会在HTTP头中使用Content-Encoding:gzip进行标识。


2. 使用Zlib模块创建类

在Node.js的Zlib模块中,提供了对gzipdeflate压缩/解压类的创建方法。详细如下:

  • 创建gzip压缩类Gzip:zlib.createGzip([options])
  • 创建gzip解压类Gunzip:zlib.createGunzip([options])
  • 创建deflate压缩类Deflate:zlib.createDeflate([options])
  • 创建deflate解压类Inflate:zlib.createInflate([options])
  • 创建deflate原始数据压缩类DeflateRaw:zlib.createDeflateRaw([options])
  • 创建deflate原始数据解压类InflateRaw:zlib.createInflateRaw([options])

在使用这些方法创建类时,都有一个Options选项,可选各项如下:

  • flush(缺省:zlib.Z_NO_FLUSH
  • chunkSize(缺省:16*1024)
  • windowBits
  • level(仅用于压缩)
  • memLevel(仅用于压缩)
  • strategy(仅用于压缩)
  • dictionary(仅用于 deflate/inflate,缺省为空目录)


3. Zlib模块中的方法

Zlib模块中,有一些方法可以方便对缓存数据或字符串进行压缩或解压处理,这些方法第一个参数为字符串或缓存,第二个可选参数可以供其内部的zlib类使用。方法提供回调和同步两种模式,回调模式下回调函数为callback(error, result)*Sync结尾的为同步方法,它接收相同参数,但没有回调函数。

  • 使用Deflate对字符串或缓存进行压缩:zlib.deflate(buf[, options], callback)、zlib.deflateSync(buf[, options])
  • 使用DeflateRaw对字符串或缓存进行压缩:zlib.deflateRaw(buf[, options], callback)、zlib.deflateRawSync(buf[, options])
  • 使用Gzip对字符串或缓存进行压缩:zlib.gzip(buf[, options], callback)、zlib.gzipSync(buf[, options])
  • 使用Gunzip对缓存进行解压:zlib.gunzip(buf[, options], callback)、zlib.gunzipSync(buf[, options])
  • 使用Inflate对缓存进行解压:zlib.inflate(buf[, options], callback)、zlib.inflateSync(buf[, options])
  • 使用InflateRaw对缓存进行解压:zlib.inflateRaw(buf[, options], callback)、zlib.inflateRawSync(buf[, options])
  • 使用Unzip对缓存进行压缩:zlib.unzip(buf[, options], callback)、zlib.unzipSync(buf[, options])


4. 使用示例

使用Zlib模块,在HTTP客户端对数据进行解压缩示例:

var zlib = require('zlib');
var http = require('http');
var fs = require('fs');
var request = http.get({ host: 'itbilu.com',
                         path: '/',
                         port: 80,
                         headers: { 'accept-encoding': 'gzip,deflate' }});
request.on('response', function(response) {
  var output = fs.createWriteStream('itbilu.com_index.html');
  switch (response.headers['content-encoding']) {
    // 可以使用zlib.createUnzip()处理两种情况
    case 'gzip':
      response.pipe(zlib.createGunzip()).pipe(output);
      break;
    case 'deflate':
      response.pipe(zlib.createInflate()).pipe(output);
      break;
    default:
      response.pipe(output);
      break;
  }
});

使用Zlib模块,创建一个HTTP服务端,根据客户端请求的编码类型,进行gzlipdeflate相应。示例如下:

var zlib = require('zlib');
var http = require('http');
var fs = require('fs');
http.createServer(function(request, response) {
  var raw = fs.createReadStream('index.html');
  var acceptEncoding = request.headers['accept-encoding'];
  if (!acceptEncoding) {
    acceptEncoding = '';
  }

  // 对客户端请求的 accept-encoding 进行简单解析(非标准的)
  if (acceptEncoding.match(/\bdeflate\b/)) {
    response.writeHead(200, { 'content-encoding': 'deflate' });
    raw.pipe(zlib.createDeflate()).pipe(response);
  } else if (acceptEncoding.match(/\bgzip\b/)) {
    response.writeHead(200, { 'content-encoding': 'gzip' });
    raw.pipe(zlib.createGzip()).pipe(response);
  } else {
    response.writeHead(200, {});
    raw.pipe(response);
  }
}).listen(1337);