node gzip

@xingbofeng 2018-04-15 07:44:52发表于 xingbofeng/xingbofeng.github.io JavaScriptNode.js

一般情况下Node.js使用zlib模块的使用gzip()压缩,但有一个坏处是,大文件会使V8缓冲区爆掉,原因是由于gzip()使用缓存,而V8的缓存区最大不超过0x3FFFFFFF字节(约为1GB),一般不使用缓存的方式压缩与解压缩数据,而使用Stream,原因可见Coding with Streams

const zlib = require('zlib');
const fs = require('fs');

fs.readFile(__dirname + '/hello.txt', 'utf-8', (readFileErr, readFileData) => {
  if (readFileErr) {
    return console.error('readFileErr error:' + readFileErr.message);
  }
  zlib.gzip(readFileData, (gzipErr, gzipData) => {
    if (gzipErr) {
      return console.error('gzipErr error:' + gzipErr.message);
    }
    fs.writeFile(__dirname + '/hello.txt.gz', gzipData, (writeFileErr) => {
      if (writeFileErr) {
        return console.error('writeFile error:' + writeFileErr.message);
      }
    });
  });
});

zlib模块同样支持gzipSync()同步方法进行压缩:

const zlib = require('zlib');
const fs = require('fs');

let readFileData;
try {
  readFileData = fs.readFileSync(__dirname + '/hello.txt', 'utf-8');
} catch (readFileErr) {
  console.error('readFileErr error:' + readFileErr.message);
}

let gzipData;
try {
  gzipData = zlib.gzipSync(readFileData);
} catch (gzipErr) {
  return console.error('gzipErr error:' + gzipErr.message);
}

try {
  fs.writeFileSync(__dirname + '/hello.txt.gz', gzipData);
} catch (writeFileErr) {
  return console.error('writeFile error:' + writeFileErr.message);
}

Node.js使用zlib模块的createGzip()创建并返回一个带有给定options的新的Gzip对象,通过这种方法,并配合Stream模块可以实现文件压缩,使用流的好处是可以实现大文件压缩,提升空间效率和时间效率:

const fs = require('fs');
const zlib = require('zlib');

const gzip = zlib.createGzip();
const readableStream = fs.createReadStream('./hello.txt');
const writeableStream = fs.createWriteStream('./hello.txt.gz');

readableStream.pipe(gzip).pipe(writeableStream);

反过来,zlib模块的createGunzip()方法可以实现解压缩:

const fs = require('fs');
const zlib = require('zlib');

const gunzip = zlib.createGunzip();
const readableStream = fs.createReadStream('./hello.txt.gz');
const writeableStream = fs.createWriteStream('./hello2.txt');

readableStream.pipe(gunzip).pipe(writeableStream);

要实现高性能的http服务,可以使用gzip对返回的静态文件进行压缩,判断HTTP报文头部是否含有accept-encoding首部,并且其值为gzip

const http = require('http');
const zlib = require('zlib');
const fs = require('fs');

const server = http.createServer((req, res) => {
  // 如果HTTP报文头部是否含有Accept-Encoding首部,并且其值为gzip
  if (req.headers['accept-encoding'].indexOf('gzip') !== -1) {
    // 设定response HTTP报文头部的Content-Encoding首部值为gzip
    res.writeHead(200, {
      'Content-Encoding': 'gzip',
    });
    // 在每次请求到来时创建Gzip
    const gzip = zlib.createGzip();
    return fs.createReadStream(__dirname + '/hello.html').pipe(gzip).pipe(res);
  }
  return fs.createReadStream(__dirname + '/hello.html').pipe(res);
});

server.listen(80, () => {
  console.log('server listen in localhost:80')
});

要在express中使用,则一般使用compression中间件:

const compression = require('compression');
const express = require('express');
const app = express();

//尽量在其他中间件前使用compression
app.use(compression());