从 Nginx 默认不压缩 HTTP/1.0 说起

简介:

在移动的 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 都会面临。

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

  1. Syntax:gzip_http_version1.0|1.1;
  2. Default:gzip_http_version1.1;
  3. Context:http,server,location
  4. SetstheminimumHTTPversionofarequestrequiredtocompressaresponse.

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

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

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 所对应的分块传输机制可以完美解决这类问题。

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

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

从 Nginx 默认不压缩 HTTP/1.0 说起

可以看到,尽管我的请求报文中指明了可以接受 GZip,但是返回的内容依然是未压缩的;同时服务端响应了 Content-Length 和 Connection: keep-alive,连接并没有断开。也就是说 Nginx 为了尽可能启用持久连接,放弃了 GZip,这是 Nginx 的默认策略。

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

从 Nginx 默认不压缩 HTTP/1.0 说起

可以看到,这次的请求报文与上次完全一样,但是结果截然不同:虽然返回的内容被压缩了,但是连接也被断开了,服务端返回了 Connection: close。原因就是之前说过的,动态压缩导致无法事先得知响应内容长度,在 HTTP/1.0 中只能依靠断开连接来让客户端知道响应结束了。

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

从 Nginx 默认不压缩 HTTP/1.0 说起

可以看到,由于请求报文是 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 来达到减少流量的目的。


原文发布时间为:2016年01月31日

本文作者:Jerry Qu的小站

本文来自云栖社区合作伙伴至顶网,了解相关信息可以关注至顶网。

相关文章
|
2月前
|
监控 网络协议 应用服务中间件
高并发下Nginx压缩
【8月更文挑战第16天】gzip压缩在Nginx中可减少传输数据量,加快响应速度但消耗CPU。可在http、server及location级别配置。高并发时,启用Nginx状态监控以检查性能,配置`nginx.conf`添加`location /NginxStatus { stub_status on; access_log off; }`并重启Nginx
41 12
|
2月前
|
缓存 应用服务中间件 API
Nginx七层(应用层)反向代理:HTTP反向代理proxy_pass篇(三)
Nginx七层(应用层)反向代理:HTTP反向代理proxy_pass篇(三)
34 3
|
2月前
|
缓存 安全 应用服务中间件
Nginx七层(应用层)反向代理:HTTP反向代理proxy_pass篇(二)
Nginx七层(应用层)反向代理:HTTP反向代理proxy_pass篇(二)
31 1
|
2月前
|
运维 算法 应用服务中间件
运维系列.Nginx中使用HTTP压缩功能(一)
运维系列.Nginx中使用HTTP压缩功能(一)
35 1
|
2月前
|
缓存 应用服务中间件 nginx
[nginx]定制http头信息
[nginx]定制http头信息
|
2月前
|
应用服务中间件 nginx
nginx配置gzip压缩
nginx配置gzip压缩
|
2月前
|
负载均衡 应用服务中间件 网络安全
Nginx七层(应用层)反向代理:HTTP反向代理proxy_pass篇(一)
Nginx七层(应用层)反向代理:HTTP反向代理proxy_pass篇(一)
86 0
|
2月前
|
缓存 应用服务中间件 nginx
运维系列.Nginx中使用HTTP压缩功能(二)
运维系列.Nginx中使用HTTP压缩功能(二)
36 0
|
2月前
|
缓存 算法 应用服务中间件
nginx搭建https服务器
nginx搭建https服务器
|
17天前
|
缓存 前端开发 JavaScript
终极 Nginx 配置指南(全网最详细)
本文详细介绍了Nginx配置文件`nginx.conf`的基本结构及其优化方法。首先通过删除注释简化了原始配置,使其更易理解。接着,文章将`nginx.conf`分为全局块、events块和http块三部分进行详细解析,帮助读者更好地掌握其功能与配置。此外,还介绍了如何通过简单修改实现网站上线,并提供了Nginx的优化技巧,包括解决前端History模式下的404问题、配置反向代理、开启gzip压缩、设置维护页面、在同一IP上部署多个网站以及实现动静分离等。最后,附上了Nginx的基础命令,如安装、启动、重启和关闭等操作,方便读者实践应用。
206 84
终极 Nginx 配置指南(全网最详细)
下一篇
无影云桌面