zlib

Node.js zlib模块免费看

zlib模块中常用的类和方法、zlib模块的使用、压缩HTTP请求和响应

2020-04-22侠课岛    基础入门       

后端/Node.js/Node.js简明入门 14     0     567

日常生活中,我们经常会用到压缩和解压文件,这样我们可以减小所压缩文件所占空间。Node.js 中提供了一个内置模块 zlib,我们可以使用这个模块来对文件进行压缩和解压。

常见压缩模式:

  • Gzip :Gzip 最早由 Jean-loup GaillyMark Adler 创建,用于 UNⅨ 系统的文件压缩。我们在Linux中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为 Internet 上使用非常普遍的一种数据压缩格式。
  • Deflate:Deflate是同时使用了 LZ77 算法与哈夫曼编码的一个无损数据压缩算法。最初是由Phil Katz为他的 PKZIP 归档工具第二版所定义的,后来定义在RFC 1951规范中。

zlib模块中常用的类和方法

  • zlib.Deflate:使用 deflate 压缩数据。
  • zlib.Gunzip:解压缩 gzip 流。
  • zlib.Gzip:使用 gzip 压缩数据。
  • zlib.Unzip:通过自动检测头信息解压 Gzip 或者 Deflate 压缩的流。
  • zlib.close([callback]):关闭基础句柄。
  • zlib.flush([kind, ]callback):刷新挂起的数据。不要轻易的调用这个方法,过早的刷新会对压缩算法造成负面影响。
  • zlib.createGunzip([options]):创建并返回一个新的 Gunzip 对象。
  • zlib.createGzip([options]):创建并返回一个新的 Gzip 对象。
  • zlib.createInflate([options]):创建并返回一个新的 Inflate 对象。
  • zlib.createUnzip([options]):创建并返回一个新的 Unzip 对象。

zlib模块的使用

zlib 模块提供通过 Gzip 和 Deflate/Inflate 以及Brotli实现的压缩功能。我们可以使用zlib模块来对数据进行压缩和解压处理,减小数据体积,加快传输速度。 使用方法如下所示:

var zlib = require('zlib');
示例:

下面我们来尝试压缩一个文件,假设现在有一个test.txt的文本文件,我们要将这个文件压缩为test.txt.gz文件。

首先呢我们肯定需要用到 zlib 模块对不对,那肯定要引入这个模块。使用zlib.createGzip() 创建并返回一个新的 Gzip 对象。

然后我们既然要压缩文件,那肯定是需要把文件中的数据也一起压缩的,那这样就需要使用到 fs 模块,通过 fs 模块创建读取流和写入流。

然后我们可以使用管倒流pipe和链式流直接完成文件读取写入和压缩操作。

代码如下所示:

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

var gzip = zlib.createGzip();

var readfile = fs.createReadStream('test.txt');
var writefile = fs.createWriteStream('test.txt.gz');

readfile.pipe(gzip)
  .on('error', () => {
    console.log("读取失败");
  })
  .pipe(writefile)
  .on('error', () => {
    console.log("写入失败");
});

除了压缩和解压文件 ,我们还可以直接压缩和解压数据,同样需要先引入 zlib 模块,因为不涉及到文件,所以不需要用fs 模块。然后我们定义一个要压缩的数据,我就简单的定义了一个data,给它赋值为”hello, xkd“。

var zlib = require('zlib');
var data = 'hello, xkd';

那我们此时的任务,就是要压缩这个data中的数据,然后再解压这个数据。然后我们可以使用zlib.gzip()来压缩数据,其中第一个参数是要压缩的数据,第二个参数是一个回调函数,在回调函数中返回错误信息。

代码如下所示:

var zlib = require('zlib');
var data = 'hello, xkd';

// data表示要压缩的数据,可以是string或buffer类型
zlib.gzip(data, (err, buffer) => {
  if (err) {
    console.log(err); 
  } 
  // buffer就是压缩后的数据对数据进行base64编码
  console.log(buffer.toString('base64')); 
  // 输出:H4sIAAAAAAAACstIzcnJ11GoyE4BAA2FiTcKAAAA

  // 对buffer数据进行解压
  zlib.unzip(buffer, (err, buffer) => {
    if (!err) {
      console.log(buffer.toString());  // 输出:hello, xkd
    } else {
      console.log(err);
    }
  });
});

压缩HTTP请求和响应

zlib 模块除了可以压缩文件和数据,还可以用来实现对 HTTP 中定义的 gzipdeflate 内容编码机制的支持。

HTTP 的 Accept-Encoding 消息头用来标记客户端接受的压缩编码。例如:

Accept-Encoding: gzip, deflate

Content-Encoding 响应头用于标识实际应用于消息的压缩编码,例如:

Content-Encoding: gzip

在浏览器与服务器的交互中,浏览器会通过请求头 Accept-Encoding 告诉服务器当前支持解压的压缩格式,例如gzip, deflate, br,多个压缩格式使用逗号隔开,服务器在接收到浏览器请求后,会按照请求头的格式压缩资源,将压缩后的资源返回,并通过响应头 Content-Encoding 告诉浏览器当前服务器压缩的格式。

示例:

客户端请求示例:

// 引入模块
var zlib = require('zlib');
var http = require('http');
var fs = require('fs');

// 发送请求
var request = http.get({ host: '9xkd.com', path: '/', port: 80,headers: { 'Accept-Encoding': 'br,gzip,deflate' } });

request.on('response', (response) => {
    var writestream = fs.createWriteStream('zlib.html');

  switch (response.headers['content-encoding']) {  // 获取客户端支持的编码
    case 'br':
      response.pipe(zlib.createBrotliDecompress()).pipe(writestream);
      break;
    case 'gzip':
      response.pipe(zlib.createGunzip()).pipe(writestream);
      break;
    case 'deflate':
      response.pipe(zlib.createInflate()).pipe(writestream);
      break;
    default:
      response.pipe(writestream);
      break;
  }
});

服务端代码示例如下所示:

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

http.createServer((request, response) => {
  const raw = fs.createReadStream('index.html');

  response.setHeader('Vary: Accept-Encoding');
  let acceptEncoding = request.headers['accept-encoding'];
  if (!acceptEncoding) {
    acceptEncoding = '';
  }
  // 匹配支持的压缩格式
  if (/\bdeflate\b/.test(acceptEncoding)) {
    response.writeHead(200, { 'Content-Encoding': 'deflate' });
    raw.pipe(zlib.createDeflate()).pipe(response);
  } else if (/\bgzip\b/.test(acceptEncoding)) {
    response.writeHead(200, { 'Content-Encoding': 'gzip' });
    raw.pipe(zlib.createGzip()).pipe(response);
  } else if (/\bbr\b/.test(acceptEncoding)) {
    response.writeHead(200, { 'Content-Encoding': 'br' });
    raw.pipe(zlib.createBrotliCompress()).pipe(response);
  } else {
    response.writeHead(200, {});
    raw.pipe(response);
  }
}).listen(8888);

从上面两段代码我们可以看出,三种对应的压缩和解压的API:

  • zlib.createDeflate()zlib.createInflate()
  • zlib.createGzip()zlib.createGunzip()
  • zlib.createBrotliCompress()zlib.createBrotliDecompress()

默认情况下,当解压不完整的数据时 zlib 方法会抛出一个错误。 如果它已经知道数据是不完整的,或者仅仅是为了检查已压缩文件的开头,可以通过改变用来解压最后一个的输入数据块的刷新方法来避免默认的错误处理:

const zlib = require('zlib');
const buffer = Buffer.from('eJzT0yMA', 'base64');

zlib.unzip(
  buffer,
  { finishFlush: zlib.constants.Z_SYNC_FLUSH },
  (err, buffer) => {
    if (!err) {
      console.log(buffer.toString());
    } else {
      console.lo(err)
    }
});

flush刷新

在压缩流上调用 flush() 方法将使 zlib 返回尽可能多的输出。虽然这样有可能会降低压缩质量,但是在需要尽快获取数据时很有用。

示例:

将部分压缩过的 HTTP 响应返回给客户端:

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

http.createServer((request, response) => {
  response.writeHead(200, { 'content-encoding': 'gzip' });
  const output = zlib.createGzip();
  output.pipe(response);

  setInterval(() => {
    output.write(`The current time is ${Date()}\n`, () => {
      output.flush();
    });
  }, 1000);
}).listen(8888);

本教程图文或视频等内容版权归侠课岛所有,任何机构、媒体、网站或个人未经本网协议授权不得转载、转贴或以其他方式复制发布或发表。

评价

14

本课评分:
  •     非常好
难易程度:
  •     适中的

内容目录


本文索引


|
教程
粉丝
主页

签到有礼

已签到2天,连续签到7天即可领取7天全站VIP

  • 1
    +2 金币
  • 2
    +3 金币
  • 3
    +5 金币
  • 6
    +7 金币
  • 5
    +6 金币
  • 4
    暖心福利
    自选分类VIP ×1天
  • 7
    惊喜大礼

    自选分类VIP ×3天 +20金币
  • 持续签到 +8 金币

金币可以用来做什么?