通过实践来聊聊利用Node怎么实现内容压缩

利用nodejs怎么实现内容压缩?下面本篇文章给大家通过实践来聊聊node侧实现内容压缩(gzip/br/deflate)的方法,希望对大家有所帮助!

通过实践来聊聊利用Node怎么实现内容压缩

在查看自己的应用日志时,发现进入日志页面后总是要几秒钟才会加载(接口没做分页),于是打开网络面板查看

1.png

2.png

点击下载“嗨格式压缩大师”;

这才发现接口返回的数据都没有被压缩,本以为接口用Nginx反向代理了,Nginx会自动帮我做这一层(这块后面探究一下,理论上是可行的)

这里的后端是 Node 服务

本文就分享一下 HTTP数据压缩相关知识以及在Node侧的实践

前置知识

下面的客户端均指浏览器

accept-encoding

3.png

客户端在向服务端发起请求时,会在请求头(request header)中添加accept-encoding字段,其值标明客户端支持的压缩内容编码格式

content-encoding

4.png

服务端在对返回内容执行压缩后,通过在响应头(response header)中添加content-encoding,来告诉浏览器内容实际压缩使用的编码算法

deflate/gzip/br

deflate是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法。

gzip 是基于 DEFLATE 的算法

br指代Brotli,该数据格式旨在进一步提高压缩比,对文本的压缩相对deflate能增加20%的压缩密度,而其压缩与解压缩速度则大致不变

zlib模块

Node.js包含一个zlib 模块,提供了使用 Gzip、Deflate/Inflate、以及 Brotli 实现的压缩功能

这里以gzip为例分场景列举多种使用方式,Deflate/Inflate与Brotli使用方式一样,只是API不一样

基于stream的操作

5.png

基于buffer的操作

6.png

引入几个所需的模块

const zlib = require('zlib')const fs = require('fs')const stream = require('stream')const testFile = 'tests/origin.log'const targetFile = `${testFile}.gz`const decodeFile = `${testFile}.un.gz`

登录后复制

文件的解/压缩

解/压缩结果查看,这里使用du指令直接统计解压缩前后结果

# 执行du -ah tests# 结果如下108K    tests/origin.log.gz2.2M    tests/origin.log2.2M    tests/origin.log.un.gz4.6M    tests

登录后复制

基于流(stream)的操作

使用createGzip与createUnzip

注:所有 zlib API,除了那些显式同步的 API,都使用 Node.js 内部线程池,可以看做是异步的因此下面的示例中的压缩和解压代码应分开执行,否则会报错

方式1: 直接利用实例上的pipe方法传递流

// 压缩const readStream = fs.createReadStream(testFile)const writeStream = fs.createWriteStream(targetFile)readStream.pipe(zlib.createGzip()).pipe(writeStream)// 解压const readStream = fs.createReadStream(targetFile)const writeStream = fs.createWriteStream(decodeFile)readStream.pipe(zlib.createUnzip()).pipe(writeStream)

登录后复制

方式2: 利用stream上的pipeline,可在回掉中单独做其它的处理

// 压缩const readStream = fs.createReadStream(testFile)const writeStream = fs.createWriteStream(targetFile)stream.pipeline(readStream, zlib.createGzip(), writeStream, err => {    if (err) {        console.error(err);    }})// 解压const readStream = fs.createReadStream(targetFile)const writeStream = fs.createWriteStream(decodeFile)stream.pipeline(readStream, zlib.createUnzip(), writeStream, err => {    if (err) {        console.error(err);    }})

登录后复制

方式3: Promise化pipeline方法

const { promisify } = require('util')const pipeline = promisify(stream.pipeline)// 压缩const readStream = fs.createReadStream(testFile)const writeStream = fs.createWriteStream(targetFile)pipeline(readStream, zlib.createGzip(), writeStream)    .catch(err => {        console.error(err);    })// 解压const readStream = fs.createReadStream(targetFile)const writeStream = fs.createWriteStream(decodeFile)pipeline(readStream, zlib.createUnzip(), writeStream)    .catch(err => {        console.error(err);    })

登录后复制

基于Buffer的操作

利用 gzip 与 unzip API,这两个方法包含同步与异步类型

压缩gzipgzipSync解压unzipunzipSync

方式1: 将readStream转Buffer,然后进行进一步操作

gzip:异步

// 压缩const buff = []readStream.on('data', (chunk) => {    buff.push(chunk)})readStream.on('end', () => {    zlib.gzip(Buffer.concat(buff), targetFile, (err, resBuff) => {        if(err){            console.error(err);            process.exit()        }        fs.writeFileSync(targetFile,resBuff)    })})

登录后复制gzipSync:同步

// 压缩const buff = []readStream.on('data', (chunk) => {    buff.push(chunk)})readStream.on('end', () => {    fs.writeFileSync(targetFile,zlib.gzipSync(Buffer.concat(buff)))})

登录后复制

方式2: 直接通过readFileSync读取

// 压缩const readBuffer = fs.readFileSync(testFile)const decodeBuffer = zlib.gzipSync(readBuffer)fs.writeFileSync(targetFile,decodeBuffer)// 解压const readBuffer = fs.readFileSync(targetFile)const decodeBuffer = zlib.gzipSync(decodeFile)fs.writeFileSync(targetFile,decodeBuffer)

登录后复制

文本内容的解/压缩

除了对文件压缩,有时候也许要对传输的内容进行直接进行解压缩

这里以压缩文本内容为例

// 测试数据const testData = fs.readFileSync(testFile, { encoding: 'utf-8' })

登录后复制

基于流(stream)操作

这块就考虑 string =>  buffer => stream的转换就行

string =>  buffer

const buffer = Buffer.from(testData)

登录后复制登录后复制

buffer => stream

const transformStream = new stream.PassThrough()transformStream.write(buffer)// orconst transformStream = new stream.Duplex()transformStream.push(Buffer.from(testData))transformStream.push(null)

登录后复制

这里以写入到文件示例,当然也可以写到其它的流里,如HTTP的Response(后面会单独介绍)

transformStream    .pipe(zlib.createGzip())    .pipe(fs.createWriteStream(targetFile))

登录后复制

基于Buffer操作

同样利用Buffer.from将字符串转buffer

const buffer = Buffer.from(testData)

登录后复制登录后复制

然后直接使用同步API进行转换,这里result就是压缩后的内容

const result = zlib.gzipSync(buffer)

登录后复制

可以写入文件,在HTTP Server中也可直接对压缩后的内容进行返回

fs.writeFileSync(targetFile, result)

登录后复制

Node Server中的实践

这里直接使用Node中 http 模块创建一个简单的 Server 进行演示

在其他的 Node Web 框架中,处理思路类似,当然一般也有现成的插件,一键接入

7.png

const http = require('http')const { PassThrough, pipeline } = require('stream')const zlib = require('zlib')// 测试数据const testTxt = '测试数据123'.repeat(1000)const app = http.createServer((req, res) => {    const { url } = req    // 读取支持的压缩算法    const acceptEncoding = req.headers['accept-encoding'].match(/(br|deflate|gzip)/g)    // 默认响应的数据类型    res.setHeader('Content-Type', 'application/json; charset=utf-8')    // 几个示例的路由    const routes = [        ['/gzip', () => {            if (acceptEncoding.includes('gzip')) {                res.setHeader('content-encoding', 'gzip')                // 使用同步API直接压缩文本内容                res.end(zlib.gzipSync(Buffer.from(testTxt)))                return            }            res.end(testTxt)        }],        ['/deflate', () => {            if (acceptEncoding.includes('deflate')) {                res.setHeader('content-encoding', 'deflate')                // 基于流的单次操作                const originStream = new PassThrough()                originStream.write(Buffer.from(testTxt))                originStream.pipe(zlib.createDeflate()).pipe(res)                originStream.end()                return            }            res.end(testTxt)        }],        ['/br', () => {            if (acceptEncoding.includes('br')) {                res.setHeader('content-encoding', 'br')                res.setHeader('Content-Type', 'text/html; charset=utf-8')                // 基于流的多次写操作                const originStream = new PassThrough()                pipeline(originStream, zlib.createBrotliCompress(), res, (err) => {                    if (err) {                        console.error(err);                    }                })                originStream.write(Buffer.from('

BrotliCompress

'))                originStream.write(Buffer.from('

测试数据

'))                originStream.write(Buffer.from(testTxt))                originStream.end()                return            }            res.end(testTxt)        }]    ]    const route = routes.find(v => url.startsWith(v[0]))    if (route) {        route[1]()        return    }    // 兜底    res.setHeader('Content-Type', 'text/html; charset=utf-8')    res.end(`

404: ${url}

    

已注册路由

    

登录后复制        ${routes.map(r => `${r[0]}`).join(”)}        `)    res.end()})app.listen(3000)

更多node相关知识,请访问:nodejs 教程!

以上就是通过实践来聊聊利用Node怎么实现内容压缩的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2632932.html

(0)
上一篇 2025年3月7日 04:15:22
下一篇 2025年2月17日 23:09:14

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • node nvm是什么

    nvm全称“node.js version management”,是一个nodejs的版本管理工具,用于解决node各种版本存在的不兼容现象,它是可以在同一台机器上安装和切换不同版本的node的工具。 本教程操作环境:windows7系统…

    2025年3月7日 编程技术
    200
  • 执行“node -v”显示node不是内部或外部命令怎么办

    解决方法:1、右击“我的电脑”,依次选择“属性”-“高级系统设置”-“高级”-“环境变量”;2、在“系统变量”中,新建一个“NODE_PATH”变量,其值为node安装路径;3、编辑Path,在变量值的尾部添加“;%NODE_PATH%”。…

    2025年3月7日 编程技术
    200
  • node中什么是mongooes

    在node中,mongooes是一个第三方模块,是一个对象文档模型(ODM)库,它对Node原生的MongoDB模块进一步的优化封装,可以通过操作对象模型来操作MongoDB数据库。 本教程操作环境:windows7系统、nodejs 12…

    2025年3月7日 编程技术
    200
  • node环境与浏览器环境的区别是什么

    区别:1、node中this指向global,而浏览器中指向window;2、Node用CommonJS标准,而浏览器用ES Modules标准;3、浏览器中的js可以操作DOM,而node中不会;4、I/O读写操作不同;5、模块加载不同。…

    2025年3月7日
    200
  • node的顶层对象是什么

    node的顶层对象是global对象。global对象是node的全局对象,该对象及其所有属性都可以在程序的任何地方访问;global对象最根本的作用是作为全局变量的宿主。 本教程操作环境:windows7系统、nodejs 12.19.0…

    2025年3月7日 编程技术
    200
  • node中fs是内置模块吗

    在node中,fs是内置模块,是指文件系统模块,用于读写文件;fs模块提供了用于满足用户对文件操作需求的方法和属性,包括文件目录的创建、删除、查询以及文件内容的读取和写入等,并且同时提供了异步和同步的方法。 本教程操作环境:windows1…

    2025年3月7日
    200
  • 安装node时会自动安装npm吗

    安装node时会自动安装npm;npm是nodejs平台默认的包管理工具,新版本的nodejs已经集成了npm,所以npm会随同nodejs一起安装,安装完成后可以利用“npm -v”命令查看是否安装成功。 本教程操作环境:windows1…

    2025年3月7日
    200
  • 什么是流(Stream)?如何理解Nodejs中的流

    什么是流?如何理解流?下面本篇文章就来带大家深入了解一下node中的流(stream),希望对大家有所帮助! 作者最近在开发中经常使用 pipe 函数,只知道这是流的管道,却不知道他是如何工作的,所以抱着一探究竟的心理干脆就从流开始学起,随…

    2025年3月7日 编程技术
    200
  • 深入聊聊node.js中的EventEmitter

    本篇文章带大家了解一下node中的eventemitter,简单聊聊一下异步操作、error事件、eventemitter类,希望对大家有所帮助! events(事件触发器) events是nodejs内置的事件触发器,在node的内置模块…

    2025年3月7日
    200
  • 深入浅析Node.js中常见的内置模块

    本篇文章带大家了解一下nodejs中常见的内置模块(路径、文件系统、events),希望对大家有所帮助! 内置模块path 路径的演练 path模块用于对路径和文件进行处理,提供了很多好用的方法 并且我们知道在Mac OS、Linux和wi…

    2025年3月7日 编程技术
    200

发表回复

登录后才能评论