Node.js实战--资源压缩与zlib模块

Blog:《NodeJS模块研究 - zlib》
nodejs 的 zlib 模块提供了资源压缩功能。例如在 http 传输过程中常用的 gzip,能大幅度减少网络传输流量,提高速度。本文将从下面几个方面介绍 zlib 模块和相关知识点:
文件压缩 / 解压
HTTP 中的压缩/解压
压缩算法:RLE
压缩算法:哈夫曼树
文件的压缩/解压
以 gzip 压缩为例,压缩代码如下:
const zlib = require("zlib");
const fs = require("fs");
const gzip = zlib.createGzip();const rs = fs.createReadStream("./db.json");
const ws = fs.createWriteStream("./db.json.gz");
rs.pipe(gzip).pipe(ws);
如下图所示,4.7Mb 大小的文件被压缩到了 575Kb。

解压刚才压缩后的文件,代码如下:
const zlib = require("zlib");
const fs = require("fs");
const gunzip = zlib.createGunzip();const rs = fs.createReadStream("./db.json.gz");
const ws = fs.createWriteStream("./db.json");
rs.pipe(gunzip).pipe(ws);
HTTP 中的压缩/解压
在服务器中和客户端的传输过程中,浏览器(客户端)通过 Accept-Encoding 消息头来告诉服务端接受的压缩编码,服务器通过 Content-Encoding 消息头来告诉浏览器(客户端)实际用于编码的算法。
服务器代码示例如下:
const zlib = require("zlib");
const fs = require("fs");
const http = require("http");
const server = http.createServer((req, res) => {
const rs = fs.createReadStream("./index.html");
// 防止缓存错乱
res.setHeader("Vary", "Accept-Encoding");
// 获取客户端支持的编码
let acceptEncoding = req.headers["accept-encoding"];
if (!acceptEncoding) {
acceptEncoding = "";
}
// 匹配支持的压缩格式
if (/\bdeflate\b/.test(acceptEncoding)) {
res.writeHead(200, { "Content-Encoding": "deflate" });
rs.pipe(zlib.createDeflate()).pipe(res);
} else if (/\bgzip\b/.test(acceptEncoding)) {
res.writeHead(200, { "Content-Encoding": "gzip" });
rs.pipe(zlib.createGzip()).pipe(res);
} else if (/\bbr\b/.test(acceptEncoding)) {
res.writeHead(200, { "Content-Encoding": "br" });
rs.pipe(zlib.createBrotliCompress()).pipe(res);
} else {
res.writeHead(200, {});
rs.pipe(res);
}
});server.listen(4000);
客户端代码就很简单了,识别 Accept-Encoding 字段,并进行解压:
const zlib = require("zlib");
const http = require("http");
const fs = require("fs");
const request = http.get({
host: "localhost",
path: "/index.html",
port: 4000,
headers: { "Accept-Encoding": "br,gzip,deflate" }
});
request.on("response", response => {
const output = fs.createWriteStream("example.com_index.html");
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">switch</span> (response.headers[<span class="hljs-string" style="color: #d14; line-height: 26px;">"content-encoding"</span>]) {
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">case</span> <span class="hljs-string" style="color: #d14; line-height: 26px;">"br"</span>:
response.pipe(zlib.createBrotliDecompress()).pipe(output);
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">break</span>;
<span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 或者, 只是使用 zlib.createUnzip() 方法去处理这两种情况:</span>
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">case</span> <span class="hljs-string" style="color: #d14; line-height: 26px;">"gzip"</span>:
response.pipe(zlib.createGunzip()).pipe(output);
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">break</span>;
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">case</span> <span class="hljs-string" style="color: #d14; line-height: 26px;">"deflate"</span>:
response.pipe(zlib.createInflate()).pipe(output);
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">break</span>;
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">default</span>:
response.pipe(output);
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">break</span>;
}
});
从上面的例子可以看出来,3 种对应的解压/压缩 API:
zlib.createInflate()和zlib.createDeflate()
zlib.createGunzip()和zlib.createGzip()
zlib.createBrotliDecompress()和zlib.createBrotliCompress()
压缩算法:RLE
RLE 全称是 Run Length Encoding, 行程长度编码,也称为游程编码。它的原理是:记录连续重复数据的出现次数。它的公式是:字符 * 出现次数。
例如原数据是 AAAAACCPPPPPPPPERRPPP,一共 18 个字节。按照 RLE 的规则,压缩后的结果是:A5C2P8E1R2P3,一共 12 个字节。压缩比例是:12 / 17 = 70.6%
RLE 的优点是压缩和解压非常快,针对连续出现的多个字符的数据压缩率更高。但对于ABCDE类似的数据,压缩后数据会更大。
压缩算法:哈夫曼树
哈夫曼树的原理是:出现频率越高的字符,用尽量更少的编码来表示。按照这个原理,以数据ABBCCCDDDD为例:
| 字符 | 编码(二进制) |
|---|---|
| D | 0 |
| C | 1 |
| B | 10 |
| A | 11 |
原来的数据是 10 个字节。那么编码后的数据是:1110101110000,一共 13bit,在计算机中需要 2 个字节来存储。这样的压缩率是:2 / 10 = 20%。
但是仅仅按照这个原理编码后的数据,无法正确还原。以前 4bit 为例,1110可以理解成:
11 + 10
1 + 1 + 1 + 0
1 + 1 + 10
...
而哈夫曼树的设计就很巧妙,能正确还原。哈夫曼树的构造过程如下:

无论哪种数据类型(文本文件、图像文件、EXE 文件),都可以采用哈夫曼树进行压缩。
参考链接

扫码关注「心谭博客」,查看「前端图谱」&「算法题解」,坚持分享,共同成长

Node.js实战--资源压缩与zlib模块的更多相关文章
- Node基础:资源压缩之zlib
概览 做过web性能优化的同学,对性能优化大杀器gzip应该不陌生.浏览器向服务器发起资源请求,比如下载一个js文件,服务器先对资源进行压缩,再返回给浏览器,以此节省流量,加快访问速度. 浏览器通过H ...
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 处理静态资源
视频地址:https://www.cctalk.com/v/15114923882788 处理静态资源 无非花开花落,静静. 指定静态资源目录 这里我们使用第三方中间件: koa-static 安装并 ...
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 错误处理
沪江CCtalk视频地址:https://www.cctalk.com/v/15114923887518 处理错误请求 爱能遮掩一切过错. 当我们在访问一个站点的时候,如果访问的地址不存在(404), ...
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 记录日志
沪江CCtalk视频地址:https://www.cctalk.com/v/15114923883523 log 日志中间件 最困难的事情就是认识自己. 在一个真实的项目中,开发只是整个投入的一小部分 ...
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 视图Nunjucks
视频地址:https://www.cctalk.com/v/15114923888328 视图 Nunjucks 彩虹是上帝和人类立的约,上帝不会再用洪水灭人. 客户端和服务端之间相互通信,传递的数据 ...
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 解析JSON
视频地址:https://www.cctalk.com/v/15114923886141 JSON 数据 我颠倒了整个世界,只为摆正你的倒影. 前面的文章中,我们已经完成了项目中常见的问题,比如 路由 ...
- iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 代码分层
视频地址:https://www.cctalk.com/v/15114923889408 文章 在前面几节中,我们已经实现了项目中的几个常见操作:启动服务器.路由中间件.Get 和 Post 形式的请 ...
- 《Node.js实战(双色)》作者之一——吴中骅访谈录
- iKcamp团队制作|基于Koa2搭建Node.js实战项目教学(含视频)☞ 环境准备
安装搭建项目的开发环境 视频地址:https://www.cctalk.com/v/15114357764004 文章 Koa 起手 - 环境准备 由于 koa2 已经开始使用 async/await ...
随机推荐
- 20191017-6 alpha week 2/2 Scrum立会报告+燃尽图 05
此作业要求参见https://edu.cnblogs.com/campus/nenu/2019fall/homework/9802 小组名称:“组长”组 组长:杨天宇 组员:魏新,罗杨美慧,王歆瑶,徐 ...
- FPGA之IO信号类型深入理解
在FPGA设计开发中,很多场合会遇到同一根信号既可以是输入信号,又可以是输出信号,即IO类型(Verilog定义成inout). 对于inout型的信号,我们既可以使用FPGA原语来实现,也可以使用V ...
- vs2015编译zlib静态库步骤
ZLIB静态库的编译 下载ZLIB源码 ZLib官网下载或者GitHub上直接 clone 下来即可 www.zlib.net 截至目前最新版本1.2.1.1本 如下图我选择从官网下载 下载完以后解压 ...
- 第 426 期 Python 周刊
文章,教程和讲座 端到端机器学习:从数据收集到模型部署 链接: https://ahmedbesbes.com/end-to-end-ml.html 在本文中,我们将完成构建和部署机器学习应用程序的必 ...
- java之set接口
1.set集合不能存储重复的元素, 2.HashSet集合不能保证的迭代顺序与元素存储顺序相同. 3.HashSet集合,采用哈希表结构存储数据,保证元素唯一性的方式依赖于:hashCode()与eq ...
- jib-maven-plugin构建镜像
序言 在本次期末设计当中,应为需要做部署脚本,我们采用的是dockerfile+docker-compose的部署方式,这种方式对vue项目是没有问题的,因为vue下载依赖与打包是分离开来的,即使修改 ...
- 12.pyecharts详细使用教程
官方数据教程: 柱状图-Bar //导入柱状图-Bar from pyecharts import Bar //设置行名 columns = ["Jan", "Feb&q ...
- Eclipse直接运行算法第4版例子(重定向和读取指定路径文件)
Eclipse直接运行算法第4版例子(重定向和读取指定路径文件) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://b ...
- 条款03:尽可能使用const
目录 1. 总结 2. const对象 3. const函数返回值和函数参数 4. const成员函数 const成员函数的重要性 bitwise constness logical constnes ...
- file_get_contents函数获取不到数据的一种情况
问题: file_get_contents($url) 获取不到数据,尽管URL地址正确,函数使用正确.如下代码 $url = "https://www.baidu.com"; ...