当前位置: 首页 > 后端技术 > Node.js

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

时间:2023-04-03 23:19:52 Node.js

?博客:《NodeJS模块研究 - zlib》?Github:https://github.com/donghubxin/blognodejs的zlib模块提供资源压缩。比如http传输过程中常用的gzip,可以大大减少网络传输流量,提高速度。本文将从以下几个方面介绍zlib模块及相关知识点:文件压缩/解压HTTP中的压缩/解压压缩算法:RLE压缩算法:哈夫曼树文件压缩/解压以gzip压缩为例,压缩代码如下如下:constzlib=require("zlib");constfs=require("fs");constgzip=zlib.createGzip();constrs=fs.createReadStream("./db.json");constws=fs.createWriteStream("./db.json.gz");rs.pipe(gzip).pipe(ws);如下图,4.7Mb的文件压缩后为575Kb。解压刚才的压缩文件,代码如下:constzlib=require("zlib");constfs=require("fs");constgunzip=zlib.createGunzip();constrs=fs.createReadStream("./db.json.gz");constws=fs.createWriteStream("./db.json");rs.pipe(gunzip).pipe(ws);HTTP中的压缩/解压在服务端和客户端传输时,浏览器(客户端)通过Accept-Encoding消息头告诉服务端它接受的压缩编码,服务端告诉浏览器(客户端)实际使用的算法通过Content-Encoding消息头进行编码。示例服务器代码如下:constzlib=require("zlib");constfs=require("fs");consthttp=require("http");constserver=http.createServer((req,res)=>{constrs=fs.createReadStream("./index.html");//防止缓存混淆res.setHeader("Vary","Accept-Encoding");//获取客户端支持的编码letacceptEncoding=req.headers["accept-encoding"];if(!acceptEncoding){acceptEncoding="";}//匹配支持的压缩格式if(/\bdeflate\b/.test(acceptEncoding)){res.writeHead(200,{"Content-Encoding":"deflate"});rs.pipe(zlib.createDeflate()).pipe(res);}elseif(/\bgzip\b/.test(acceptEncoding)){res.writeHead(200,{"Content-Encoding":"gzip"});rs.pipe(zlib.createGzip()).pipe(res);}elseif(/\bbr\b/.test(acceptEncoding)){res.writeHead(200,{"Content-Encoding":"br"});rs.pipe(zlib.createBrotliCompress()).pipe(res);}else{res.writeHead(200,{});rs.pipe(res);}});服务器。听(4000);客户端代码很简单,识别Accept-Encoding字段并解压:constzlib=require("zlib");consthttp=require("http");constfs=require("fs");constrequest=http.get({host:"localhost",path:"/index.html",port:4000,headers:{"Accept-Encoding":"br,gzip,deflate"}});request.on("响应",response=>{constoutput=fs.createWriteStream("example.com_index.html");switch(response.headers["content-encoding"]){case"br":response.pipe(zlib.createBrotliDecompress()).pipe(output);break;//或者,只使用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;}});从上面的例子可以看出,3种对应的解压/压缩API:zlib.createInflate()和zlib.createDeflate()zlib.createGunzip()和zlib.createGzip()zlib.createBrotliDecompress()和zlib.createBrotliCompress()压缩算法:RLERLE全称RunLengthEncoding,游程编码,也称为游程编码。它的原理是:记录连续重复数据出现的次数。它的公式是:字符*出现次数。比如原始数据是AAAAACCCPPPPPPPPPPERRPPP,一共18个字节。根据RLE的规则,压缩后的结果为:A5C2P8E1R2P3,共12个字节。压缩比为:12/17=70.6%RLE的优点是压缩和解压都非常快,对于连续出现的多个字符数据压缩比更高。但是对于类似ABCDE的数据,压缩后数据会比较大。压缩算法:哈夫曼树哈夫曼树的原理是:出现频率高的字符用尽可能少的代码表示。根据这个原理,以数据ABBCCCCDDDD为例:字符编码(二进制)D0C1B10A11的原始数据为10个字节。那么编码后的数据为:1110101110000,共13位,需要2个字节才能存入计算机。这样的压缩比为:2/10=20%。但是,仅仅按照这个原则编码的数据是无法正确恢复的。以4bit为例,1110可以理解为:11+101+1+1+01+1+10...而且哈夫曼树的设计非常巧妙,可以正确还原。哈夫曼树的构建过程如下:无论是什么类型的数据(文本文件、图像文件、EXE文件),都可以使用哈夫曼树进行压缩。参考链接Nodejs文档30分钟HTTP检漏补全Vary程序员必备硬核知识百科?扫描二维码关注“心坛博客”,查看“前端地图”&“算法题解”,坚持分享,共同成长?