Rumah >hujung hadapan web >tutorial js >Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihan

Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihan

青灯夜游
青灯夜游ke hadapan
2022-03-08 20:00:582088semak imbas

Bagaimana untuk mencapai pemampatan kandungan menggunakan Nodejs? Artikel berikut akan bercakap tentang kaedah melaksanakan pemampatan kandungan (gzip/br/deflate) di bahagian Node melalui amalan saya harap ia akan membantu anda!

Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihan

Apabila menyemak log aplikasi saya, saya mendapati ia sentiasa mengambil masa beberapa saat untuk dimuatkan selepas memasuki halaman log (antara muka tidak penomboran). Jadi saya membuka panel rangkaian dan menyemak

Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihan

Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihan

hanya untuk mendapati bahawa data yang dikembalikan oleh antara muka tidak dimampatkan menyangka antara muka menggunakan proksi terbalik Nginx , Nginx secara automatik akan membantu saya melakukan lapisan ini (saya akan meneroka ini kemudian, secara teorinya boleh dilaksanakan)

Ujung belakang di sini ialah perkhidmatan Node >

Artikel ini adalah Kongsi

pengetahuan berkaitan dan prapengetahuan dalam HTTP数据压缩Node侧的实践

Pelanggan berikut semuanya merujuk kepada penyemak imbas

pengekodan terima

Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihan

Apabila klien memulakan permintaan ke pelayan, ia akan menambah medan

dalam pengepala permintaan dan nilainya menunjukkan klien accept-encodingformat支持的压缩内容编码

pengekodan kandungan

Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihan

Selepas pelayan melakukan pemampatan pada kandungan yang dikembalikan, ia memberitahu penyemak imbas dengan menambahkan

pada respons pengepala. Kandungan bekas content-encoding实际压缩使用的编码算法

deflate/gzip/br

ialah algoritma pemampatan data tanpa kehilangan yang menggunakan kedua-dua algoritma deflate dan LZ77. 哈夫曼编码(Huffman Coding)

ialah algoritma berdasarkan gzip DEFLATE

merujuk kepada br Format data ini direka untuk meningkatkan lagi nisbah mampatan dan boleh memampatkan teks secara relatif Brotli Tingkatkan ketumpatan mampatan deflate, manakala kelajuan mampatan dan penyahmampatannya kekal hampir tidak berubah20%

modul zlib

Node.js mengandungi

, yang menyediakan penggunaan zlib 模块, dan GzipDeflate/InflateBrotliDi sini kami mengambil

sebagai contoh untuk menyenaraikan pelbagai kaedah penggunaan mengikut senario

dan gzip digunakan dengan cara yang sama , tetapi API berbezaDeflate/Inflate Brotli

Operasi berdasarkan

stream

Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihan

Operasi berdasarkan

buffer

Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihanMemperkenalkan beberapa modul yang diperlukan

Menyahkod/memampatkan fail
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`

Melihat hasil penyahmampatan/mampatan, di sini gunakan

perintah untuk mengira terus penyahmampatan Sebelum dan selepas keputusan

du

berdasarkan
# 执行
du -ah tests

# 结果如下
108K    tests/origin.log.gz
2.2M    tests/origin.log
2.2M    tests/origin.log.un.gz
4.6M    tests
operasi

流(stream) menggunakan

dengan

createGzipcreateUnzip

NOTA: Semua
    API kecuali API yang disegerakkan secara eksplisit semuanya menggunakan kumpulan benang dalaman Node.js, yang boleh dianggap sebagai tak segerak
  • zlib Oleh itu, kod mampatan dan penyahmampatan dalam contoh berikut hendaklah dilaksanakan secara berasingan, jika tidak, ralat akan dilaporkan
Kaedah 1:

Terus gunakan kaedah pada contoh untuk lulus strim 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)
Kaedah 2 :

Gunakan pada , anda boleh melakukan pemprosesan lain secara berasingan dalam panggilan balik streampipeline

// 压缩
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);
    }
})
Kaedah 3:

Promise kaedah pipeline

Operasi berdasarkan
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);
    })

BufferMenggunakan

dan

API, kedua-dua kaedah ini termasuk gzip dan unzip jenis 同步异步

Mampatan
    • gzip
    • gzipSync
    Nyahzip
    • unzip
    • unzipSync
Kaedah 1:

Tukar kepada , dan kemudian lakukan operasi selanjutnya readStreamBuffer

gzip: tak segerak
// 压缩
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: Segerakkan
// 压缩
const buff = []
readStream.on('data', (chunk) => {
    buff.push(chunk)
})
readStream.on('end', () => {
    fs.writeFileSync(targetFile,zlib.gzipSync(Buffer.concat(buff)))
})
Kaedah 2:

Baca terus readFileSync penyahmampatan /mampatan kandungan teks melalui

>
// 压缩
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)
Selain pemampatan fail, kadangkala ia mungkin perlu untuk menyahmampatkan kandungan yang dipindahkan secara langsung

这里以压缩文本内容为例

// 测试数据
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)

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

Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihan

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(&#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)

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

Atas ialah kandungan terperinci Mari kita bincangkan tentang cara menggunakan Node untuk mencapai pemampatan kandungan melalui latihan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:juejin.cn. Jika ada pelanggaran, sila hubungi admin@php.cn Padam