当前位置: 首页 > 科技观察

探秘HTTP传输中gzip压缩的秘密

时间:2023-03-16 15:22:29 科技观察

为什么要开启gZip我们给别人发邮件的时候,我们在传输前压缩自己的文件,收件人收到后解压文件。这种手术对我们来说已经司空见惯。我们压缩文件的目的是减少传输文件的大小,加快传输速度。在http传输中启用gZip的目的也是如此,但是一般的文章在介绍gZip的时候,总是结合一些服务器端的配置(nginx)或者构建工具插件(webpack),罗列一大堆配置在云端给人看的一头雾水,以至于到头来一直不明白为什么要用,怎么用这些问题。http和gZip下面我们来讨论这些问题gZip文件是如何通信的,然后去解压文件。我们使用的浏览器在http传输的过程中起到了解压文件的作用,但是浏览器是如何区分文件的格式的,应该用什么格式来解压呢?在http/1.0协议中,可以为服务器发送的数据配置一个Content-Encoding字段。该字段用于描述数据压缩方式Content-Encoding:gzipContent-Encoding:compressContent-Encoding:deflate客户端收到返回的数据,然后查看对应字段的信息,然后根据对应的格式做对应的解码。当客户端请求时,它可以使用Accept-Encoding字段来表示它接受哪些压缩方法。Accept-Encoding:gzip,deflate我们可以在浏览器的控制台看到请求的相关信息Compatibility说到浏览器作为前端,我不禁想到一个问题,有没有浏览器不支持吗?HTTP/1.0于1996年5月发布,好消息是基本不用考虑兼容性问题,几乎所有的浏览器都支持。值得一提的是,在早期的ie6版本中有一个bug会破坏gZip。后来ie6自己在WinXPSP2中修复了这个问题,使用这个版本的用户也很少。看来谁来压缩文件这件事只能在服务器端完成了。我们在网上看到的最多的是nginx启用gZip配置之类的文章,但是现在前端spa应用流行,使用react、vue等框架总是伴随着这套自己的脚手架,一般都是使用webpack作为打包工具,可以配置compression-webpack-plugin等插件,它可以让我们将生成的文件用gZip进行压缩,生成对应的压缩文件,而我们在构建的时候应用,可以在里面放置一层node应用接口鉴权和文件转发的服务区和前端文件。nodejs中我们熟悉的express框架还有一个压缩中间件,可以启用gZip,一时间看得人眼花缭乱,谁用谁用,怎么用?服务端响应请求时的压缩其实nginx压缩和在node框架中使用中间件进行压缩是一样的。当我们点击一??个网页发送请求时,我们的服务器会找到对应的文件,然后压缩文件并返回压缩后的文件。【当然可以使用缓存来减少压缩次数】,配置我们上面提到的Content-Encoding信息。对于某些应用程序,构建时没有上游代理层。比如服务端可以直接使用自带的压缩插件,只用一层node来压缩文件。如果上游配置了nginx转发处理层,最好交给nginx来处理这些,因为他们有专门为此构建的内容,更好地利用缓存,减少开销(很多用c写的)。让我们看看在nginx中启用gZip压缩的一些配置#Opengzipgzipon;#启用gzip压缩最小文件,小于设定值的文件不压缩gzip_min_length1k;#gzip压缩级别,1-10,数字越大压缩效果越好,占用CPU时间越多,后面会详细介绍gzip_comp_level2;#要压缩的文件类型。JavaScript有多种形式。这些值可以在mime.types文件中找到。gzip_typestext/plainapplication/javascriptapplication/x-javascripttext/cssapplication/xmltext/javascript;应用构建时的压缩既然服务端可以做,为什么webpack在打包前端应用的时候要有这么一个压缩插件呢?我们可以在上面的nginx配置中看到gzip_comp_level2配置项,上面也有注释,写着1-10。数字越大,压缩效果越好,但会消耗更多的CPU和时间。除了减小文件大小外,我们还压缩文件以减少传输时间。如果我们将压缩级别配置得非常高。每次请求请求,服务器都要压缩很长时间才能返回信息。不仅服务器开销会增加很多,请求者也会很不耐烦。但是由于现在spa应用的文件都是打包生成的,如果我们在打包的时候直接生成一个高压缩文件,作为静态资源放在服务器上,收到请求后直接返回压缩文件内容呢?关于什么?webpack的compression-webpack-plugin就是这样做的。它的配置也非常简单。您只需要在设备上添加相应的插件即可。简单配置如下:constCompressionWebpackPlugin=require('compression-webpack-plugin');webpackConfig.plugins.push(newCompressionWebpackPlugin({asset:'[path].gz[query]',algorithm:'gzip',test:newRegExp('\\.(js|css)$'),threshold:10240,minRatio:0.8}))webpackpackaging打包文件生成后,会额外生成一个.gz后缀的压缩文件。那么这个插件的压缩级别是多少呢?我们在源码中可以看到默认级别是9...constzlib=require('zlib');this.options.algorithm=zlib[this.options.algorithm];...this.options.compressionOptions={level:options.level||9,flush:options.flush...}可以看到压缩是使用了zlib库,而在zlib分类方面,默认是6,最高级别是9Bestcompression(也是zlib.Z_BEST_COMPRESSION),因为我们只在项目上线的时候回去打包构建一次,所以我们使用构建时最高级别的压缩压缩的方式不花费我们任何时间,我们也不需要再在服务器上压缩文件,我们只需要找到对应的压缩文件直接返回即可。如何在服务器端找到这些文件,在应用层面解决这个问题就比较简单了。比如上面的压缩文件会生成index.css和index.js的压缩文件。服务器端简单处理就可以判断这两个请求,然后给出相应的压缩文件。以node的express为例...app.get(['/index.js','/index.css'],function(req,res,next){req.url=req.url+'.gz'res.set('Content-Encoding','gzip')res.setHeader("Content-Type",generateType(req.path))//这里需要根据请求文件设置content-typenext())上面我们可以给请求返回gZip压缩后的数据。当然,上述限制太强,不可取,但已经有很多库存可以应对这种需求。Express有express-static-gzip插件koa。gZip文件检测的基本原理是先检测请求是否存在.gz后缀的文件,然后根据结果返回不同的内容。gZip可以压缩哪些文件gZip可以压缩所有文件,但这并不意味着我们需要压缩所有文件。我们写的代码(css,js)等文件会有很好的压缩效果,但是图片之类的文件不会被gzip压缩太多,因为它们已经内置了一些压缩功能,有些文件(比如一些已经像.zip文件一样压缩)解压缩可能会使生成的文件更大。当然,本来就很小的文件就没必要再压缩了。如果在实践中可以启用gZip,则必须启用它。具体是在请求时实时压缩还是在构建时生成压缩文件取决于你的具体业务情况。参考资料zlib、gzip和zip有什么关系?它们有什么共同点,它们有何不同?webpackgzipvsexpressgzip什么是gZip压缩?协议