Als ich meine eigenen Anwendungsprotokolle überprüfte, stellte ich fest, dass das Laden nach dem Aufrufen der Protokollseite immer einige Sekunden dauerte (die Schnittstelle ist nicht paginiert), also öffnete ich zur Überprüfung das Netzwerkfenster
Reverse
-Proxy verwendet und Nginx mir bei dieser Ebene automatisch helfen würde (ich werde das später untersuchen, es ist theoretisch machbar).
Hier ist Node. Service
Dieser Artikel vermittelt Wissen über HTTP数据压缩
und Node侧的实践
. Die folgenden Clients beziehen sich alle auf die Browser
Wenn der Client eine Anfrage an den Server initiiert, fügt er dem Anfrageheader das Feld accept-encoding
hinzu, dessen Wert支持的压缩内容编码
实际压缩使用的编码算法
, indem er dem Antwortheader content-encoding
hinzufügt und
sowohl den LZ77
-Algorithmus als auch哈夫曼编码(Huffman Coding)
A deflate
verwendet Datenkomprimierungsalgorithmus basierend auf哈夫曼编码(Huffman Coding)
.
gzip
ist ein auf DEFLATE
basierender Algorithmus
. br
bezieht sich auf Brotli
. Dieses Datenformat zielt darauf ab, das Komprimierungsverhältnis im Vergleich zu deflate
weiter zu verbessern. Die Komprimierungsdichte von Text kann um 20%
erhöht werden, während die Komprimierungs- und Dekomprimierungsgeschwindigkeit in etwa unverändert
Node.js enthält ein zlib 模块
, das mit Gzip
, Deflate/Inflate
und Brotli
Deflate/Inflate
Brotli
gzip
als Beispiel verwendet, um verschiedene Verwendungsmethoden entsprechend den verwendeten Szenarien aufzulisten Auf die gleiche Weise, aber die API
basiert auf stream
buffer
Operationen
Führen Sie mehrere erforderliche Module
ein 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
# Führen Sie du -ah-Tests aus # Die Ergebnisse lauten wie folgt: 108K Tests/origin.log.gz 2,2 Mio. Tests/Origin.log 2,2 Mio. Tests/origin.log.un.gz 4.6M testet
流(stream)
basierte Vorgängemit createGzip
und createUnzip
zlib
APIs, mit Ausnahme derjenigen, die explizit synchron sind, verwenden den internen Thread-Pool von Node.js und können als asynchron betrachtet werden,Methode 1: Verwenden Sie direkt die pipe
Methode auf der Instanz, um den Stream zu übertragen
// Komprimierung const readStream = fs.createReadStream(testFile) const writeStream = fs.createWriteStream(targetFile) readStream.pipe(zlib.createGzip()).pipe(writeStream) // Const dekomprimieren readStream = fs.createReadStream(targetFile) const writeStream = fs.createWriteStream(decodeFile) readStream.pipe(zlib.createUnzip()).pipe(writeStream)
Methode 2: Mithilfe pipeline
im stream
können Sie andere Verarbeitungen separat im Rückruf durchführen
// Komprimierung const readStream = fs.createReadStream(testFile) const writeStream = fs.createWriteStream(targetFile) stream.pipeline(readStream, zlib.createGzip(), writeStream, err => { if (irre) { console.error(err); } }) // Const dekomprimieren readStream = fs.createReadStream(targetFile) const writeStream = fs.createWriteStream(decodeFile) stream.pipeline(readStream, zlib.createUnzip(), writeStream, err => { if (irre) { console.error(err); } })
Methode 3: Promise pipeline
-Methode
const { promisify } = require('util') const Pipeline = versprechen(stream.pipeline) // Const komprimieren readStream = fs.createReadStream(testFile) const writeStream = fs.createWriteStream(targetFile) Pipeline(readStream, zlib.createGzip(), writeStream) .catch(err => { console.error(err); }) // Const dekomprimieren readStream = fs.createReadStream(targetFile) const writeStream = fs.createWriteStream(decodeFile) Pipeline(readStream, zlib.createUnzip(), writeStream) .catch(err => { console.error(err); })
Buffer
Vorgängenutzen gzip
und unzip
-APIs. Diese beiden Methoden umfassen同步
und异步
Typkomprimierung.
gzip
gzipSync
unzip
unzipSync
-
Methode 1: Konvertieren Sie readStream
in Buffer
und führen Sie dann weitere Vorgänge aus
readStream.on('data', (chunk) => { buff.push(chunk) }) readStream.on('end', () => { zlib.gzip(Buffer.concat(buff), targetFile, (err, resBuff) => { if(err){ console.error(err); prozess.exit() } fs.writeFileSync(targetFile,resBuff) }) })
// Komprimierung const buff = [] readStream.on('data', (chunk) => { buff.push(chunk) }) readStream.on('end', () => { fs.writeFileSync(targetFile,zlib.gzipSync(Buffer.concat(buff))) })
Methode 2: Direkt über readFileSync
lesen
// Komprimierte Konstante readBuffer = fs.readFileSync(testFile) const decodeBuffer = zlib.gzipSync(readBuffer) fs.writeFileSync(targetFile,decodeBuffer) // Const dekomprimieren readBuffer = fs.readFileSync(targetFile) const decodeBuffer = zlib.gzipSync(decodeFile) fs.writeFileSync(targetFile,decodeBuffer)
Zusätzlich zur Dateikomprimierung kann es manchmal erforderlich sein, den übertragenen Inhalt direkt zu dekomprimieren.
Hier ist der komprimierte Textinhalt als Beispiel
// Testdaten const testData = fs. readFileSync( testFile, {kodierung: 'utf-8' })Betrachten Sie
流(stream)
-Operationeneinfach die Konvertierung von string
=> buffer
=> stream
string
=> buffer
const buffer = Buffer.from(testData)
buffer
=> stream
const transformStream = neuer Stream.PassThrough() transformStream.write(Puffer) // oder const transformStream = new stream.Duplex() transformStream.push(Buffer.from(testData)) transformStream.push(null)
Hier ist ein Beispiel für das Schreiben in eine Datei. Natürlich kann es auch in andere Streams geschrieben werden, z. B. HTTP的Response
(wird später separat vorgestellt)
transformStream .pipe(zlib.createGzip()) .pipe(fs.createWriteStream(targetFile))
verwendet auch Buffer.from
, um die buffer
Buffer
const buffer = Buffer.from(testData)zu konvertieren
, und verwendet dann direkt die Synchronisierungs-API für die Konvertierung content
const result = zlib.gzipSync(buffer)
kann Dateien schreiben, und im HTTP Server
kann der komprimierte Inhalt auch direkt zurückgegeben werden
fs.writeFileSync(targetFile, result)
Hier verwenden wir direkt das http
Modul im Node zum Erstellen Ein einfacher Server Für Demonstrationen
in anderen Node Web
-Frameworks sind die Verarbeitungsideen ähnlich. Natürlich gibt es im Allgemeinen vorgefertigte Plug-Ins, auf die mit einem Klick zugegriffen werden kann.
const http = require('http') const { PassThrough, Pipeline } = require('stream') const zlib = require('zlib') //Testdaten const testTxt = 'Testdaten 123'.repeat(1000) const app = http.createServer((req, res) => { const { url } = req // Den unterstützten Komprimierungsalgorithmus lesen const AcceptEncoding = req.headers['accept-encoding'].match(/(br|deflate|gzip)/g) //Standard-Antwortdatentyp res.setHeader('Content-Type', 'application/json; charset=utf-8') // Mehrere Beispielrouten const Routen = [ ['/gzip', () => { if (acceptEncoding.includes('gzip')) { res.setHeader('content-encoding', 'gzip') // Synchronisierungs-API verwenden, um Textinhalte direkt zu komprimieren res.end(zlib.gzipSync(Buffer.from(testTxt))) zurückkehren } res.end(testTxt) }], ['/deflate', () => { if (acceptEncoding.includes('deflate')) { res.setHeader('content-encoding', 'deflate') // Einzeloperation basierend auf Stream const originStream = new PassThrough() originStream.write(Buffer.from(testTxt)) originStream.pipe(zlib.createDeflate()).pipe(res) originStream.end() zurückkehren } res.end(testTxt) }], ['/br', () => { if (acceptEncoding.includes('br')) { res.setHeader('content-encoding', 'br') res.setHeader('Content-Type', 'text/html; charset=utf-8') // Mehrere Schreibvorgänge basierend auf Streams const originStream = new PassThrough() Pipeline(originStream, zlib.createBrotliCompress(), res, (err) => { if (irre) { console.error(err); } }) originStream.write(Buffer.from('<h1>BrotliCompress</h1>')) originStream.write(Buffer.from('<h2>Testdaten</h2>')) originStream.write(Buffer.from(testTxt)) originStream.end() zurückkehren } res.end(testTxt) }] ] const route = Routen.find(v => url.startsWith(v[0])) if (Route) { Route[1]() zurückkehren } // Zurück zum Anfang res.setHeader('Content-Type', 'text/html; charset=utf-8') res.end(`<h1>404: ${url}</h1> <h2>Registrierte Route</h2> <ul> ${routes.map(r => `<li><a href="${r[0]}">${r[0]}</a></li>`).join('') } </ul> `) res.end() }) app.listen(3000)