从 Nginx 默认不压缩 HTTP/1.0 提及

转自:  https://imququ.com/post/why-nginx-disable-gzip-in-http10.html?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.iohtml

 

从 Nginx 默认不压缩 HTTP/1.0 提及

临近年关,明显变忙,博客也更新得慢了,之后尽可能保证周更吧。今天这篇文章属于计划以外的更新,源自于白天看到的《一个基于 http 协议的优化》。在这篇文章中,做者描述了这样一个现象:nginx

在 移动的 http 请求量和联通不相上下的前提下,移动的 http response 带来的网络流量是联通的 2.5 倍。移动大概有 3 成的请求都没有作压缩,而联通几乎都是通过压缩的。那些没有通过压缩的 http 会话都是走了 1.0 的协议,相反通过压缩的 http 会话都是走了 http1.1 协议。浏览器

也就是说在相同的服务端配置下,移动运营商过来的流量中有 30% 走了 HTTP/1.0,而做者所使用的 HTTP Server,不对 HTTP/1.0 响应启用 GZip。性能优化

为何在移动运营商网络下会有这么高比例的 HTTP/1.0 请求,本文按下不表,总之这必定是移动的缘由。直接看另一个问题,也就是本文标题所写:Nginx 为何默认不压缩 HTTP/1.0?网络

那篇文章的做者并无说明他用什么 HTTP Server,我这里直接当成 Nginx 好了。后面会发现这个问题跟 HTTP 协议有关,全部 HTTP Server 都会面临。post

在 Nginx 的官网文档中,有这样一个指令:性能

Syntax: gzip_http_version 1.0 | 1.1;
Default: gzip_http_version 1.1;
Context: http, server, location
Sets the minimum HTTP version of a request required to compress a response.测试

很明显,这个指令是用来设置 Nginx 启用 GZip 所需的 HTTP 最低版本,默认是 HTTP/1.1。也就是说 Nginx 默认不压缩 HTTP/1.0 是由于这个指令,将它的值改成 1.0 就能解决问题。优化

对于文本文件,GZip 的效果很是明显,开启后传输所需流量大约会降至 1/4 ~ 1/3。这么好的事情,Nginx 改一下配置就能够支持,为何它默认不开启?ui

Nginx 对于知足条件(请求头中有 Accept-Encoding: gzip,响应内容的 Content-Type 存在于 gzip_types 列表)的请求会采用即时压缩(On-The-Fly Compression),整个压缩过程在内存中完成,是流式的。也就是说,Nginx 不会等文件 GZip 完成再返回响应,而是边压缩边响应,这样能够显著提升 TTFB(Time To First Byte,首字节时间,WEB 性能优化重要指标)。这样惟一的问题是,Nginx 开始返回响应时,它没法知道将要传输的文件最终有多大,也就是没法给出 Content-Length 这个响应头部。

咱们还知道,HTTP/1.1 默认支持 TCP 持久链接(Persistent Connection),HTTP/1.0 也能够经过显式指定 Connection: keep-alive 来启用持久链接。HTTP 运行在 TCP 链接之上,天然也有着跟 TCP 同样的三次握手、慢启动等特性,为了尽量的提升 HTTP 性能,使用持久链接就显得尤其重要了。

明白以上两点,问题就水落石出了。对于 TCP 持久链接上的 HTTP 报文,客户端须要一种机制来准确判断结束位置,而在 HTTP/1.0 中,这种机制只有 Content-Length。因而,前面这种状况只能要么不压缩,要么不启用持久链接(对于非持久链接,TCP 断开就能够认为 HTTP 报文结束),而 Nginx 默认选择的是前者。

那么在 HTTP/1.1 中,这个问题解决了吗?固然!我在以前的文章中讲过,HTTP/1.1 新增的 Transfer-Encoding: chunked 所对应的分块传输机制能够完美解决这类问题。有兴趣的同窗能够查看个人这篇文章:HTTP 协议中的 Transfer-Encoding

理论知识先写到这里,最后用实践来验证一下:

首先,不启用 Nginx 的 HTTP/1.0 GZip 功能,使用 HTTP/1.0 请求报文测试:

http/1.0 without gzip

能够看到,尽管个人请求报文中指明了能够接受 GZip,可是返回的内容依然是未压缩的;同时服务端响应了 Content-LengthConnection: keep-alive,链接并无断开。也就是说 Nginx 为了尽量启用持久链接,放弃了 GZip,这是 Nginx 的默认策略。

而后,启用 Nginx 的 HTTP/1.0 GZip 功能,使用 HTTP/1.0 请求报文测试:

http/1.0 with gzip

能够看到,此次的请求报文与上次彻底同样,可是结果大相径庭:虽然返回的内容被压缩了,可是链接也被断开了,服务端返回了 Connection: close。缘由就是以前说过的,动态压缩致使没法事先得知响应内容长度,在 HTTP/1.0 中只能依靠断开链接来让客户端知道响应结束了。

最后,使用 HTTP/1.1 请求报文测试:

http/1.1 with gzip

能够看到,因为请求报文是 HTTP/1.1 的,Nginx 能知道这个客户端能够支持 HTTP/1.1 的 Transfer-Encoding: chunked,因而经过分块传输解决了全部问题:既启用了压缩,也启用了持久链接。

那么,对于 HTTP/1.0 请求,咱们是让 Nginx 放弃持久链接好,仍是放弃 GZip 好呢?

实际上,因为 HTML 文档通常都是使用 PHP、Node.js 等动态语言输出,即便不压缩,Nginx 也没法事先得知它的 Content-Length,在 HTTP/1.0 中横竖都没法启用持久链接,这时还不如启用 GZip 省点流量。

对 于 JS、CSS 等事先能够知道大小的静态文本文件,个人建议是,移动端首次访问把重要的 JS、CSS 都内联在 HTML 中,而后存在 localStorage 里,后续不输出;不重要的 JS、CSS 外链并启用 GZip,牺牲 keep-alive 来达到减小流量的目的。

本文先写到这里,欢迎来博客原文进行评论、交流。浏览器的 GZip 其实还有不少有趣的小故事,先卖个关子,之后有空再写。

本文连接:https://imququ.com/post/why-nginx-disable-gzip-in-http10.html参与评论

--EOF--

相关文章
相关标签/搜索