HTTP压缩

HTTP压缩是一种内置到网页服务器和网页客户端中以改进传输速度和带宽利用率的方式。

HTTP数据在从服务器发送前就已压缩：兼容的浏览器将在下载所需的格式前宣告支持何种方法给服务器；不支持压缩方法的浏览器将下载未经压缩的数据。最常见的压缩方案包括brotli、gzip和Deflate，但可用方案的完整列表由IANA维护。此外，第三方可能开发新的方法并纳入到其自身的产品，例如Google的面向HTTP共享字典压缩（SDCH）方案就实现在Google Chrome浏览器和使用在Google的服务器上。

在HTTP中有两种不同的方式可以完成压缩。在较低层级，Transfer-Encoding头可以指示HTTP消息的有效载荷被压缩。在较高层级，Content-Encoding头可以指示一个被转码、缓存或引用的资源已压缩。使用Content-Encoding的压缩比Transfer-Encoding有更广泛的支持，并且某些浏览器不宣告Transfer-Encoding压缩以避免触发服务器的缺陷。

## 压缩方案协商

在大多数情况中（不包括SDCH），协商使用两个步骤完成，这描述在RFC 2616：

- 网页客户端在HTTP请求的头部通告其支持的压缩方案为一个标记列表（tokens）。对于Content-Encoding，这个列表称作Accept-Encoding；对于Transfer-Encoding，该字段被称为TE。

```http
GET /encrypted-area HTTP/1.1
Host: www.example.com
Accept-Encoding: gzip, deflate
```

- 如果服务器支持一种或多种压缩方案，输出的数据可能用一种或多种双方支持的方法压缩。如果是这种情况，服务器将在HTTP响应中添加一个Content-Encoding或Transfer-Encoding字段表明使用的方案，用逗号分隔。

```http
HTTP/1.1 200 OK
Date: Tue, 27 Feb 2018 06:03:16 GMT
Server: Apache/1.3.3.7 (Unix)  (Red-Hat/Linux)
Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
Accept-Ranges: bytes
Content-Length: 438
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Encoding: gzip
```

网页服务器本身没有义务使用任何压缩方法——这取决于网页服务器的内部设置，并可能依赖于网站的内部架构。

在SDCH的情况下，完成一份字典协商也是必须的，其中可能涉及额外的步骤，比如从外部服务器下载一个合适的字典。

## Content-Encoding标记

服务器和客户端的标记（token）的官方列表由IANA维护，它包括：

- compress – UNIX的“compress”程序的方法（历史性，不推荐大多数应用使用，应该使用gzip或deflate）
- deflate – 基于deflate算法（定义于RFC 1951）的压缩，使用zlib数据格式（RFC 1950）封装
- exi – W3C高效XML交换
- gzip – GNU zip格式（定义于RFC 1952）。此方法截至2011年3月，是应用程序支持最广泛的方法。
- identity – 不转换内容。这是内容编码的默认值。
- pack200-gzip – 传输Java存档文件的网络传输格式

除此之外，一些非官方或非标准化的标记也已被一些服务器或客户端使用：

- br – Brotli，一种新的开源压缩算法，专为HTTP内容的编码而设计，已在Mozilla Firefox 44中实现，并且Chromium正准备实施。
- bzip2 – 基于自由格式bzip2的压缩，被lighttpd支持。
- lzma – 基于原始LZMA的压缩，在Opera 20中可用，elinks使用一个编译时选项也可启用。
- peerdist – Microsoft对等端内容缓存和检索
- sdch – Google的面向HTTP共享字典压缩，基于VCDIFF（RFC 3284）；在最近的Google Chrome、Chromium和Android版本中原生支持，并被Google的网站支持。
- xpress - Windows商店（Windows 8及之后版本）的应用程序更新时使用的微软压缩协议。可选使用一个霍夫曼编码的基于LZ77的压缩。
- xz - 基于LZMA2的内容压缩，Firefox可使用非官方补丁支持；mget自从2013年12月31日已完整实现。

## 支持HTTP压缩的服务器

- SAP NetWeaver
- Microsoft IIS：内置或使用第三方模块
- Apache HTTP Server，通过 mod_deflate（正如其名，只支持gzipself-published source?）
- Hiawatha HTTP server：服务器预先压缩文件
- Cherokee HTTP server，即时完成gzip和deflate压缩
- Oracle iPlanet Web Server
- Zeus Web Server
- lighttpd，通过mod_compress和较新的mod_deflate（1.5.x）
- nginx – 内置
- 基于Tornado的应用程序，如果“compress_response”在应用设置中设置为True（对4.0之前的版本，设置“gzip”为True）
- Jetty Server – 内置到默认的静态内容服务并在servlet过滤器配置中可用
- GeoServer
- Apache Tomcat
- IBM Websphere
- AOLserver
- Ruby Rack，通过Rack::Deflater中间件
- Varnish – 内置。也可配合ESI

HTTP中的压缩也可以使用服务器脚本语言（例如PHP；或者编程语言，例如Java）来实现。

## 阻碍使用HTTP压缩的问题

2009年Google工程师Arvind Jain和Jason Glasgow的文章指出，每天有超过99人年的时间由于用户没有接收到已压缩内容而增加的页面加载时间而浪费。这可能发生于：反病毒软件检查连接导致内容变为未压缩；使用代理服务器（网页服务器为保兼容性而放弃压缩）；服务器配置不当；浏览器遇到问题而停止使用压缩。Internet Explorer 6在使用代理服务器时会回退到使用HTTP 1.0（没有压缩、流水线等特性）——这是企业环境中的常见配置——这也是主流浏览器最常遇到的，回落到未压缩HTTP的情况。

另一个大规模部署HTTP压缩遇到的问题是，deflate编码的定义：HTTP 1.1将deflate编码定义为将deflate压缩（RFC 1951）的数据放入一个zlib格式的数据流（RFC 1950），而微软服务器和客户端产品历来将它实现为“原样”（"raw"）数据流，这使其部署是不可靠的。出于此原因，部分软件（包括Apache HTTP Server）只实现gzip编码。

## 安全问题

2012年，一种对数据压缩不利的普遍性攻击被公布，被称为CRIME。CRIME攻击可能对大量协议产生效果，包括但不限于TLS以及应用层协议（例如SPDY或HTTP）。只有针对TLS和SPDY的攻击被论证，并且在浏览器和服务器中得到了大幅缓解。CRIME利用的HTTP压缩没有得到全面的缓解，即使CRIME的作者已经警告说，该漏洞的影响范围可能比SPDY和TLS的压缩更广泛。

2013年，涉及HTTP压缩的CRIME攻击新实例被发布，被称为BREACH。BREACH攻击可以在30秒内从TLS加密的网页流量中提取登录令牌、电子邮件地址或其他敏感信息（时间取决于要提取的字节数），这也可能使攻击者诱骗受害者访问恶意的网站链接。TLS和SSL的所有版本都受到了BREACH的影响，无论使用何种加密算法或密码本。不同于以往的CRIME实例，那些都可以通过关闭TLS压缩或SPDY头压缩缓解攻击；BREACH利用的HTTP压缩基本上不能关闭，因为几乎所有网页服务器都依赖它提高与用户的数据传输速度。

## 外部链接

- RFC 2616: Hypertext Transfer Protocol – HTTP/1.1
- HTTP Content-Coding Values by Internet Assigned Numbers Authority
- Compression with lighttpd
- Coding Horror: HTTP Compression on IIS 6.0
- 15 Seconds: Web Site Compression at the Wayback Machine （2011年7月16日存档）
- HTTP Compression: resource page by the founder of VIGOS AG, Constantin Rack
- Using HTTP Compression by Martin Brown of Server Watch
- Using HTTP Compression in PHP
- Dynamic and static HTTP compression with Apache httpd
- Browser HTTP Compression Test
- Check HTTP compression
- Check Gzip Compression Online