Node を使用してコンテンツ圧縮を実現する方法を実践しながら話しましょう

青灯夜游
リリース: 2022-03-11 20:05:54
転載
2034 人が閲覧しました

Nodejs を使用してコンテンツ圧縮を実現するにはどうすればよいですか?以下の記事では、Node側でコンテンツ圧縮(gzip/br/deflate)を実装する方法を実践しながら解説していきますので、ご参考になれば幸いです。

Node を使用してコンテンツ圧縮を実現する方法を実践しながら話しましょう

アプリケーションのログを確認すると、ログ ページに入ってからロードするのに常に数秒かかることがわかりました (インターフェイスはページ分割されていません)。そこで、ネットワーク パネルを開いて、

Node を使用してコンテンツ圧縮を実現する方法を実践しながら話しましょう

Node を使用してコンテンツ圧縮を実現する方法を実践しながら話しましょう

# を確認したところ、インターフェイスから返されたデータが圧縮されていないことがわかりました。インターフェイスには Nginx リバース プロキシが使用されていると考えられました。Nginx はこのレイヤーの実行を自動的に支援します (これについては後で検討します。理論的には実現可能です)

ここでのバックエンドは Node Service

です。

この記事では、HTTP データ圧縮関連の知識と ノード側での実践を共有します

事前知識

次の内容クライアントはすべてブラウジングを指します

accept-encoding

Node を使用してコンテンツ圧縮を実現する方法を実践しながら話しましょう

クライアントがサーバーへのリクエストを開始すると、リクエストに ## が追加されます#accept-encoding フィールドの値は、クライアントがサポートする圧縮コンテンツ エンコーディング 形式 content-encoding

Node を使用してコンテンツ圧縮を実現する方法を実践しながら話しましょう を示します。

サーバーは、返されたコンテンツの圧縮を実行した後、応答ヘッダーに

content-encoding を追加することで、コンテンツの実際の圧縮に使用されるエンコード アルゴリズム をブラウザーに伝えます。 deflate/gzip/br

deflate

は、LZ77 アルゴリズムと ハフマン コーディング ロスレス データ圧縮アルゴリズムの両方を使用するものです。

gzip

は、DEFLATE に基づくアルゴリズムです。

br

は、データ Brotli を参照します。 format 圧縮率をさらに向上させることを目的として、テキストを圧縮すると、deflate に比べて圧縮密度が 20% 増加しますが、圧縮速度と解凍速度はほぼ変わりません zlib module

Node.js には、

Gzip

Deflate/InflateBrotli へのアクセスを提供する zlib モジュールが含まれています 実装された圧縮関数 ここでは

gzip

を例に、シナリオに応じたさまざまな利用方法を列挙します。 Brotli ですが、API は異なります stream

に基づく操作

Node を使用してコンテンツ圧縮を実現する方法を実践しながら話しましょうbuffer に基づく

操作

必要なモジュールをいくつか紹介

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`
ログイン後にコピー
Node を使用してコンテンツ圧縮を実現する方法を実践しながら話しましょうファイルを解凍/圧縮する

Unzip/ 圧縮結果を表示するには、ここで

du

コマンドを使用して、解凍前後の結果を直接カウントします。

# 执行
du -ah tests

# 结果如下
108K    tests/origin.log.gz
2.2M    tests/origin.log
2.2M    tests/origin.log.un.gz
4.6M    tests
ログイン後にコピー

stream(stream)## に基づく操作

# createGzip および createUnzip

注: 明示的に同期される API を除く、すべての zlib API , Node.js の内部スレッド プールを使用します。非同期とみなされます

    したがって、次の例の圧縮コードと解凍コードは別々に実行する必要があります。そうしないとエラーが報告されます
  • 方法 1:
  • サンプルを直接使用する
  • // 压缩
    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)
    ログイン後にコピー

pipe メソッドを使用する 方法 2: pipeline

を使用する

stream で返される 他の処理を個別に実行する

// 压缩
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: Promiseizationpipeline

Method

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);
    })
ログイン後にコピー
Operation Buffer

gzip および unzip

API に基づいて、これら 2 つのメソッドには

synchronousasynchronous# が含まれます##types 圧縮gzip

    • gzipSync
    • 解凍
    • unzip
  • ##unzipSync
    • 方法 1:
    • readStreamTransfer
    • 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: synchronous
// 压缩
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)

// 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('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 教程

以上がNode を使用してコンテンツ圧縮を実現する方法を実践しながら話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート