目錄
#前置知識
accept-encoding
content-encoding
解/壓縮結果查看,這裡使用
的操作#使用
利用gzip
基于流(stream)操作
基于Buffer操作
Node Server中的实践
BrotliCompress
测试数据
404: ${url}
已注册路由
首頁 web前端 js教程 透過實踐聊聊利用Node怎麼實現內容壓縮

透過實踐聊聊利用Node怎麼實現內容壓縮

Mar 08, 2022 pm 08:00 PM
node

利用Nodejs怎麼實作內容壓縮?以下這篇文章給大家透過實作來聊聊Node側實作內容壓縮(gzip/br/deflate)的方法,希望對大家有幫助!

透過實踐聊聊利用Node怎麼實現內容壓縮

在查看自己的應用程式日誌時,發現進入日誌頁面後總是要幾秒鐘才會載入(介面沒做分頁),於是打開網路面板查看

透過實踐聊聊利用Node怎麼實現內容壓縮

透過實踐聊聊利用Node怎麼實現內容壓縮

這才發現介面回傳的資料都沒有被壓縮,本來以為介面用Nginx反向代理了,Nginx會自動幫我做這一層(這塊後面探究一下,理論上是可行的)

這裡的後端是Node 服務

本文就分享一下HTTP資料壓縮相關知識以及在Node側的實踐

#前置知識

下面的客戶端均指瀏覽器

accept-encoding

透過實踐聊聊利用Node怎麼實現內容壓縮

#客戶端在向服務端發起請求時,會在請求頭(request header)中加入accept-encoding字段,其值標示客戶端支援的壓縮內容編碼格式

content-encoding

透過實踐聊聊利用Node怎麼實現內容壓縮

##服務端在對返回內容執行壓縮後,透過在回應頭(response header)中加入

content-encoding,來告訴瀏覽器內容實際壓縮使用的編碼演算法

#deflate/gzip/br

deflate是同時使用了LZ77演算法與哈夫曼編碼(Huffman Coding)的一個無損資料壓縮演算法。

gzip 是基於DEFLATE 的演算法

br指涉Brotli,該資料格式旨在進一步提高壓縮比,對文字的壓縮相對deflate能增加20%的壓縮密度,而其壓縮與解壓縮速度則大致不變

zlib模組

Node.js包含一個

zlib 模組,提供了使用GzipDeflate/Inflate、以及Brotli 實作的壓縮功能

這裡以

gzip為例分場景列舉多種使用方式,Deflate/InflateBrotli使用方式一樣,只是API不一樣

基於stream的操作

透過實踐聊聊利用Node怎麼實現內容壓縮

##基於

buffer 的操作

透過實踐聊聊利用Node怎麼實現內容壓縮引入幾個所需的模組

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

指令直接統計解壓縮前後結果<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'># 执行 du -ah tests # 结果如下 108K tests/origin.log.gz 2.2M tests/origin.log 2.2M tests/origin.log.un.gz 4.6M tests</pre><div class="contentsignin">登入後複製</div></div>基於

流(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(&#39;util&#39;)
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,這兩個方法包含同步異步類型 壓縮

  • gzip
    • gzipSync
    • 解壓縮
  • #unzip
    • unzipSync
  • #方式1:

readStreamBuffer,然後進行進一步操作gzip:非同步

    // 压缩
    const buff = []
    readStream.on(&#39;data&#39;, (chunk) => {
        buff.push(chunk)
    })
    readStream.on(&#39;end&#39;, () => {
        zlib.gzip(Buffer.concat(buff), targetFile, (err, resBuff) => {
            if(err){
                console.error(err);
                process.exit()
            }
            fs.writeFileSync(targetFile,resBuff)
        })
    })
    登入後複製
  • gzipSync:同步
    #
    // 压缩
    const buff = []
    readStream.on(&#39;data&#39;, (chunk) => {
        buff.push(chunk)
    })
    readStream.on(&#39;end&#39;, () => {
        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: &#39;utf-8&#39; })
登入後複製

基于流(stream)操作

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

string => buffer

const buffer = Buffer.from(testData)
登入後複製
登入後複製

buffer => stream

const transformStream = new stream.PassThrough()
transformStream.write(buffer)

// or
const 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 框架中,处理思路类似,当然一般也有现成的插件,一键接入

透過實踐聊聊利用Node怎麼實現內容壓縮

const http = require(&#39;http&#39;)
const { PassThrough, pipeline } = require(&#39;stream&#39;)
const zlib = require(&#39;zlib&#39;)

// 测试数据
const testTxt = &#39;测试数据123&#39;.repeat(1000)

const app = http.createServer((req, res) => {
    const { url } = req
    // 读取支持的压缩算法
    const acceptEncoding = req.headers[&#39;accept-encoding&#39;].match(/(br|deflate|gzip)/g)

    // 默认响应的数据类型
    res.setHeader(&#39;Content-Type&#39;, &#39;application/json; charset=utf-8&#39;)

    // 几个示例的路由
    const routes = [
        [&#39;/gzip&#39;, () => {
            if (acceptEncoding.includes(&#39;gzip&#39;)) {
                res.setHeader(&#39;content-encoding&#39;, &#39;gzip&#39;)
                // 使用同步API直接压缩文本内容
                res.end(zlib.gzipSync(Buffer.from(testTxt)))
                return
            }
            res.end(testTxt)
        }],
        [&#39;/deflate&#39;, () => {
            if (acceptEncoding.includes(&#39;deflate&#39;)) {
                res.setHeader(&#39;content-encoding&#39;, &#39;deflate&#39;)
                // 基于流的单次操作
                const originStream = new PassThrough()
                originStream.write(Buffer.from(testTxt))
                originStream.pipe(zlib.createDeflate()).pipe(res)
                originStream.end()
                return
            }
            res.end(testTxt)
        }],
        [&#39;/br&#39;, () => {
            if (acceptEncoding.includes(&#39;br&#39;)) {
                res.setHeader(&#39;content-encoding&#39;, &#39;br&#39;)
                res.setHeader(&#39;Content-Type&#39;, &#39;text/html; charset=utf-8&#39;)
                // 基于流的多次写操作
                const originStream = new PassThrough()
                pipeline(originStream, zlib.createBrotliCompress(), res, (err) => {
                    if (err) {
                        console.error(err);
                    }
                })
                originStream.write(Buffer.from(&#39;<h1 id="BrotliCompress">BrotliCompress</h1>&#39;))
                originStream.write(Buffer.from(&#39;<h2 id="测试数据">测试数据</h2>&#39;))
                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(&#39;Content-Type&#39;, &#39;text/html; charset=utf-8&#39;)
    res.end(`<h1 id="nbsp-url">404: ${url}</h1>
    <h2 id="已注册路由">已注册路由</h2>
    <ul>
        ${routes.map(r => `<li><a href="${r[0]}">${r[0]}</a></li>`).join(&#39;&#39;)}
    </ul>
    `)
    res.end()
})

app.listen(3000)
登入後複製

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

以上是透過實踐聊聊利用Node怎麼實現內容壓縮的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

nvm 怎麼刪除node nvm 怎麼刪除node Dec 29, 2022 am 10:07 AM

nvm刪除node的方法:1、下載「nvm-setup.zip」並將其安裝在C碟;2、設定環境變量,並透過「nvm -v」指令查看版本號;3、使用「nvm install」指令安裝node;4、透過「nvm uninstall」指令刪除已安裝的node即可。

node專案中如何使用express來處理檔案的上傳 node專案中如何使用express來處理檔案的上傳 Mar 28, 2023 pm 07:28 PM

怎麼處理文件上傳?以下這篇文章為大家介紹一下node專案中如何使用express來處理文件的上傳,希望對大家有幫助!

Node服務怎麼進行Docker鏡像化?極致優化詳解 Node服務怎麼進行Docker鏡像化?極致優化詳解 Oct 19, 2022 pm 07:38 PM

這段時間在開發一個騰訊文檔全品類通用的HTML 動態服務,為了方便各品類接入的生成與部署,也順應上雲的趨勢,考慮使用Docker 的方式來固定服務內容,統一進行製品版本的管理。這篇文章就將我在服務 Docker 化的過程中累積起來的優化經驗分享出來,供大家參考。

深入淺析Node的進程管理工具'pm2” 深入淺析Node的進程管理工具'pm2” Apr 03, 2023 pm 06:02 PM

這篇文章跟大家分享Node的進程管理工具“pm2”,聊聊為什麼需要pm2、安裝和使用pm2的方法,希望對大家有幫助!

Pi Node教學:什麼是Pi節點?如何安裝和設定Pi Node? Pi Node教學:什麼是Pi節點?如何安裝和設定Pi Node? Mar 05, 2025 pm 05:57 PM

PiNetwork節點詳解及安裝指南本文將詳細介紹PiNetwork生態系統中的關鍵角色——Pi節點,並提供安裝和配置的完整步驟。 Pi節點在PiNetwork區塊鏈測試網推出後,成為眾多先鋒積極參與測試的重要環節,為即將到來的主網發布做準備。如果您還不了解PiNetwork,請參考Pi幣是什麼?上市價格多少? Pi用途、挖礦及安全性分析。什麼是PiNetwork? PiNetwork項目始於2019年,擁有其專屬加密貨幣Pi幣。該項目旨在創建一個人人可參與

聊聊用pkg將Node.js專案打包為執行檔的方法 聊聊用pkg將Node.js專案打包為執行檔的方法 Dec 02, 2022 pm 09:06 PM

如何用pkg打包nodejs可執行檔?以下這篇文章跟大家介紹一下使用pkg將Node專案打包為執行檔的方法,希望對大家有幫助!

npm node gyp失敗怎麼辦 npm node gyp失敗怎麼辦 Dec 29, 2022 pm 02:42 PM

npm node gyp失敗是因為“node-gyp.js”跟“Node.js”版本不匹配,其解決辦法:1、透過“npm cache clean -f”清除node快取;2、透過“npm install -g n”安裝n模組;3、透過「n v12.21.0」指令安裝「node v12.21.0」版本即可。

什麼是單一登入系統?用nodejs怎麼實作? 什麼是單一登入系統?用nodejs怎麼實作? Feb 24, 2023 pm 07:33 PM

什麼是單一登入系統?用nodejs怎麼實作?以下這篇文章為大家介紹一下使用node實作單一登入系統的方法,希望對大家有幫助!

See all articles