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 ...
随机推荐
- 洛谷$P3302$ 森林 $[SDOI2013]$ 主席树
正解:主席树 解题报告: 传送门! 口胡一时爽代码火葬场 这题想法不难,,,但显然的是代码应该还挺难打的 但反正我也不放代码,就写下题解趴$QwQ$ 第一问就是个$Count\ on\ a\ tree ...
- 远程管理服务器--批量管理服务器,vps
一般大型的企事业单位都有自己的服务器,但是服务器一般都放在机房,辐射较大,噪音大,如何能有效的避免这一情况呢?哈哈,那就来个远程桌面,远程操作服务器吧. 一.使用 iis7远程连接管理工具工具下载官网 ...
- 「Poj1845」Sumdiv 解题报告
题面戳这里 啥都别看,只是求 \(a^b\)所有的因数的和 思路: 真没想到! 其实我们可以先将\(a^b\)分解成质因数的 因为\(a^b\)的因数肯定是\(a^b\)的质因数在一定的条件下相乘而成 ...
- 探究Dubbo的拓展机制: 上
这篇博文是我决心深度学习Dubbo框架时记录的笔记, 主题是Dubbo的拓展点, 下面的几个部分相对来说比较零散, 貌似是不和主题挂钩的 , 并且是一些很冷门的知识点 , 但是它们确实是深入学习Dub ...
- key_load_public: invalid format
ssh-keygen -f ~/.ssh/id_rsa -y > ~/.ssh/id_rsa.pub
- 【转】分布式服务框架 Zookeeper -- 管理分布式环境中的数据
Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集群管理.分布式应用配置项的管理 ...
- 如何制作地图故事使用esri story maps
博客作者原创 制作方法如下:http://url.cn/5dnsVQd
- 字符串String类常见算法题
1.将一个字符串进行反转.将字符串中指定部分进行反转. public class StringDemo { //方式一:转换为char[] public String reverse(String s ...
- Android反编译三件套 apktool 、dex2jar、jd-gui
1.还是老话下载三件套(点击下载) 或者自己在百度搜索下载 2.使用apktool反编译apk cd到D:\TESTCODE\android\android反编译三件套目录下 输入java -jar ...
- MySQL/数据库 知识点总结
书籍推荐 <SQL基础教程(第2版)> (入门级) <高性能MySQL : 第3版> (进阶) 文字教程推荐 SQL Tutorial (SQL语句学习,英文).SQL Tut ...