Heim > Web-Frontend > js-Tutorial > Hauptteil

Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können

青灯夜游
Freigeben: 2022-03-11 20:05:54
nach vorne
2033 Leute haben es durchsucht

Wie erreicht man eine Inhaltskomprimierung mit Nodejs? Der folgende Artikel wird über die Methode zur Implementierung der Inhaltskomprimierung (gzip/br/deflate) auf der Node-Seite in der Praxis sprechen. Ich hoffe, er wird Ihnen hilfreich sein!

Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können

Als ich mein Anwendungsprotokoll überprüfte, stellte ich fest, dass das Laden nach dem Aufrufen der Protokollseite immer ein paar Sekunden dauerte (die Benutzeroberfläche war nicht paginiert), also öffnete ich das Netzwerkfenster, um nachzusehen

Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können

Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können

dies Erst dann stellte ich fest, dass die von der Schnittstelle zurückgegebenen Daten nicht komprimiert waren. Ich dachte, dass die Schnittstelle den Nginx-Reverse-Proxy verwendet und Nginx mir automatisch bei dieser Ebene helfen würde (das werde ich später untersuchen). theoretisch machbar)

Das Backend hier ist Node Service

In diesem Artikel wird das Wissen über HTTP-Datenkomprimierung und die Praxis auf der Node-SeiteHTTP数据压缩相关知识以及在Node侧的实践

前置知识

下面的客户端均指浏览器

accept-encoding

Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können

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

content-encoding

Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können

服务端在对返回内容执行压缩后,通过在响应头(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的操作

Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können

基于buffer的操作

Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können

引入几个所需的模块

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`
Nach dem Login kopieren

文件的解/压缩

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

# 执行
du -ah tests

# 结果如下
108K    tests/origin.log.gz
2.2M    tests/origin.log
2.2M    tests/origin.log.un.gz
4.6M    tests
Nach dem Login kopieren

基于流(stream)的操作

使用createGzipcreateUnzip

  • 注:所有 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)
Nach dem Login kopieren

方式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);
    }
})
Nach dem Login kopieren

方式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);
    })
Nach dem Login kopieren

基于Buffer的操作

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

  • 压缩
    • gzip
    • gzipSync
  • 解压
    • unzip
    • unzipSync

方式1:readStreamBuffer,然后进行进一步操作

  • 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)
    })
})
Nach dem Login kopieren
  • gzipSync:同步
// 压缩
const buff = []
readStream.on('data', (chunk) => {
    buff.push(chunk)
})
readStream.on('end', () => {
    fs.writeFileSync(targetFile,zlib.gzipSync(Buffer.concat(buff)))
})
Nach dem Login kopieren

方式2: 直接通过readFileSyncPre-End Knowledge

Die folgenden Clients beziehen sich alle auf Browser

accept-encoding

Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können

🎜Wenn der Client Initiiert eine Anfrage an den Server und enthält den Anfrage-Header. Fügen Sie das Feld accept-encoding im (Anfrage-Header) hinzu, dessen Wert das unterstützte komprimierte Inhaltskodierungsformat des Clients angibt 🎜

content -encoding

🎜Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können🎜🎜Nachdem der Server die Komprimierung des zurückgegebenen Inhalts durchgeführt hat, teilt er dem Browserinhalt den für die tatsächliche Komprimierung verwendeten Codierungsalgorithmus< mit, indem er <code>content hinzufügt -encoding zum Antwortheader. /code>🎜

deflate/gzip/br

🎜deflate verwendet beide LZ77-Algorithmus und Huffman Coding ist ein verlustfreier Datenkomprimierungsalgorithmus. 🎜🎜gzip ist ein Algorithmus, der auf DEFLATE basiert. 🎜🎜br bezieht sich auf Brotli, ein Datenformat, das entwickelt wurde Um das Komprimierungsverhältnis weiter zu verbessern, kann die Textkomprimierung die Komprimierungsdichte im Vergleich zu deflate um 20 % erhöhen, während die Komprimierungs- und Dekomprimierungsgeschwindigkeit ungefähr gleich bleibt🎜

zlib-Modul 🎜🎜Node.js enthält ein zlib-Modul, das die Verwendung von Gzip, Deflate/Inflate ermöglicht , und Von Brotli implementierte Komprimierungsfunktion🎜🎜Hier nehmen wir gzip als Beispiel, um verschiedene Verwendungsmethoden je nach Szenario aufzulisten, Deflate/Inflate und Brotli</code >Die Verwendung ist die gleiche, aber die API ist anders🎜🎜<strong>Betrieb basierend auf <code>stream🎜🎜Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können🎜🎜Operationen basierend auf Puffer</ Code></strong>🎜🎜<img src="https://img.php.cn/upload/image/734/331/536/164674055924407Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können" title="164674055924407Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können" alt="Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können "/>🎜🎜Führen Sie mehrere erforderliche Module ein 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">// 压缩 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)</pre><div class="contentsignin">Nach dem Login kopieren</div></div><h2 data-id="heading-6">Dateidekomprimierung/-komprimierung🎜🎜Dekomprimierungs-/Komprimierungsergebnisse anzeigen, hier verwenden Sie den Befehl <code>du, um direkt zu zählen die Ergebnisse vor und nach der Dekomprimierung🎜
// 测试数据
const testData = fs.readFileSync(testFile, { encoding: &#39;utf-8&#39; })
Nach dem Login kopieren
Nach dem Login kopieren

Operationen basierend auf stream

🎜Verwenden Sie createGzip und createUnzip 🎜
  • Hinweis: Alle zlib-APIs, mit Ausnahme derjenigen, die explizit synchron sind, verwenden den internen Thread-Pool von Node.js und können als asynchron betrachtet werden
  • Also Die folgenden Komprimierungs- und Dekomprimierungscodes im Beispiel sollten separat ausgeführt werden, andernfalls wird ein Fehler gemeldet
🎜Methode 1: Verwenden Sie direkt die Pipe</code >-Methode auf der Instanz, um den Stream zu übergeben🎜 <div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">const buffer = Buffer.from(testData)</pre><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div>🎜<strong>Methode 2:</strong> Mit der <code>Pipeline auf stream können Sie andere Verarbeitungen während des Streams separat durchführen Rollback🎜
const transformStream = new stream.PassThrough()
transformStream.write(buffer)

// or
const transformStream = new stream.Duplex()
transformStream.push(Buffer.from(testData))
transformStream.push(null)
Nach dem Login kopieren
Nach dem Login kopieren
🎜Methode 3: Promise pipeline-Methode🎜
transformStream
    .pipe(zlib.createGzip())
    .pipe(fs.createWriteStream(targetFile))
Nach dem Login kopieren
Nach dem Login kopieren

Operation basierend auf Puffer< /h3>🎜Verwenden Sie die APIs gzip und unzip. Diese beiden Methoden umfassen die Typen synchron und asynchronous🎜
  • Komprimierung
    • gzip
    • gzipSync
  • Entpacken< ul>
  • unzip
  • unzipSync
🎜Methode 1 : Wird < code>readStream in den Puffer umwandeln und dann weitere Vorgänge ausführen🎜
  • gzip: asynchronous
const buffer = Buffer.from(testData)
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
  • gzipSync: synchronisiert< /li>
const result = zlib.gzipSync(buffer)
Nach dem Login kopieren
Nach dem Login kopieren
🎜Methode 2: Lesen Sie 🎜
fs.writeFileSync(targetFile, result)
Nach dem Login kopieren
Nach dem Login kopieren
🎜Dekomprimierung/Komprimierung von Textinhalten direkt über readFileSync🎜🎜In Zusätzlich zur Dateikomprimierung, manchmal vielleicht, um den übertragenen Inhalt direkt zu dekomprimieren🎜

这里以压缩文本内容为例

// 测试数据
const testData = fs.readFileSync(testFile, { encoding: &#39;utf-8&#39; })
Nach dem Login kopieren
Nach dem Login kopieren

基于流(stream)操作

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

string => buffer

const buffer = Buffer.from(testData)
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

buffer => stream

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

// or
const transformStream = new stream.Duplex()
transformStream.push(Buffer.from(testData))
transformStream.push(null)
Nach dem Login kopieren
Nach dem Login kopieren

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

transformStream
    .pipe(zlib.createGzip())
    .pipe(fs.createWriteStream(targetFile))
Nach dem Login kopieren
Nach dem Login kopieren

基于Buffer操作

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

const buffer = Buffer.from(testData)
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

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

const result = zlib.gzipSync(buffer)
Nach dem Login kopieren
Nach dem Login kopieren

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

fs.writeFileSync(targetFile, result)
Nach dem Login kopieren
Nach dem Login kopieren

Node Server中的实践

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

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

Lassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können

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>BrotliCompress</h1>&#39;))
                originStream.write(Buffer.from(&#39;<h2>测试数据</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>404: ${url}</h1>
    <h2>已注册路由</h2>
    <ul>
        ${routes.map(r => `<li><a href="${r[0]}">${r[0]}</a></li>`).join(&#39;&#39;)}
    </ul>
    `)
    res.end()
})

app.listen(3000)
Nach dem Login kopieren

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

Das obige ist der detaillierte Inhalt vonLassen Sie uns darüber sprechen, wie Sie mit Node durch Übung eine Inhaltskomprimierung erreichen können. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:juejin.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage