使用node.js压缩流优化http请求

作者: 拾起落叶好过冬 | 来源:发表于2018-06-12 23:28 被阅读9次

    前端性能优化一直是一个值得讨论的话题,而节省每次HTTP请求的流量,则是优化的一个重要的点,比如javascript文件、图片、样式表等进行压缩传输,不仅使访问速度更快,也可以有效的节省站点的流量。

    HTTP的请求中带有一个头Content-Encoding来处理压缩。

    常见的压缩模式:

    • GZIP
    • Deflate

    GZIP

    GZIP最早由Jean-loup Gailly和Mark Adler创建,用于UNⅨ系统的文件压缩。我们在Linux中经常会用到后缀为.gz的文件,它们就是GZIP格式的。现今已经成为Internet 上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    Deflate

    DEFLATE是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法。
    它最初是由Phil Katz为他的PKZIP归档工具第二版所定义的,后来定义在RFC 1951规范中。

    在node.js中使用压缩流

    node.js中已经为我们提供了压缩的功能,它的核心功能在zlib包里。

    zlib模块提供通过 Gzip 和 Deflate/Inflate 实现的压缩功能。

    使用方法

    const zlib = require('zlib');
    const fs = require('fs');
    const path = require('path');
    
    let file = path.join(__dirname, './1.txt');
    zip(file);
    
    function zip(file) {
      let gzip = zlib.createGzip(); //gzip是一个转换流
      fs.createReadStream(file).pipe(gzip).pipe(fs.createWriteStream(file + '.gz'));
    }
    
    

    可以看到用法非常简单,使用createGzip可以创建一个gzip压缩流,它是一个Transform转换流。首先使用待压缩的目标文件创建一个可读流,将它pipe到gzip压缩流中,再pipe到一个可写流中,即可完成压缩。运行这段代码可以看到在模块目录下已经多了一个1.txt.gz的压缩包。

    unzip(path.join(__dirname, './1.txt.gz'));
    function unzip(file) {
      let gunzip = zlib.createGunzip(file);
      fs.createReadStream(file).pipe(gunzip).pipe(fs.createWriteStream(path.basename(file, '.gz')));
    }
    

    解压缩同样如此,使用解压缩流即可。

    使用压缩优化http请求

    了解了压缩流的使用,怎么样才能配合http来优化用户的请求呢?

    http有一个字段,它描述了浏览器支持哪种压缩格式:

    Accept-Encoding: gzip, deflate, br
    

    响应头

    Content-Encoding: gzip
    

    处理流程:

    1. 首先查看http请求头Accept-Encoding都支持哪些压缩格式
    2. 根据不同的压缩格式将资源压缩并输出到浏览器
    3. 对不同的压缩格式发送响应头Content-Encoding

    实例代码:

    const http = require('http');
    const url = require('url');
    const path = require('path');
    const fs = require('fs');
    const zlib = require('zlib');
    
    let server = http.createServer((req, res) => {
      let {pathname} = url.parse(req.url, true);
    
      if (pathname === '/') {
        res.end('请访问一个服务器上的文件 如http://localhost:3000/1.txt');
      }
    
      let file = path.join(__dirname, pathname);
    
      fs.stat(file, (err, stat) => {
        if (err) {
          res.end('访问的文件不存在');
        } else {
    
          let acceptEncoding = req.headers['accept-encoding']; //取得浏览器的accept-encoding头,询问支持哪种压缩
          if (acceptEncoding.match(/\bgzip\b/)) { //浏览器支持gzip格式
            res.setHeader('Content-Encoding', 'gzip'); //告知浏览器发送的数据是gzip压缩格式
            let gzip = zlib.createGzip();
            fs.createReadStream(file).pipe(gzip).pipe(res); //压缩后输出
          } else if (acceptEncoding.match(/\bdeflate\b/)) { //浏览器支持deflate格式
            let deflate = zlib.createDeflate();
            res.setHeader('Content-Encoding','deflate');
            fs.createReadStream(file).pipe(deflate).pipe(res); 压缩后输出
          } else {
            fs.createReadStream(file).pipe(res);
          }
        }
      });
    });
    
    server.listen(3000, () => {
      console.log('服务器已启动在3000端口...')
    });
    

    重要代码说明:

    let acceptEncoding = req.headers['accept-encoding'];
    

    取得浏览器的请求头,查看支持哪些压缩格式,因为某些老旧浏览器是不支持压缩的,因此要针对不同的压缩格式分别处理。

    if (acceptEncoding.match(/\bgzip\b/)) {
    

    使用正则来进行判断,看看是否支持gzip压缩

    res.setHeader('Content-Encoding', 'gzip'); //告知浏览器发送的数据是gzip压缩格式
    

    使用setHeader来设置响应头,告知浏览器此数据是经gzip压缩的,这样浏览器才会正确处理,否则浏览器并不识别gzip数据。

    deflate格式的逻辑完全一样,这样就可以做到http压缩以节省流量的目的。

    相关文章

      网友评论

        本文标题:使用node.js压缩流优化http请求

        本文链接:https://www.haomeiwen.com/subject/szldeftx.html