HTTP(HyperText Transfer Protocol,超文本传输协议)是Web的基础协议,我们每天浏览网页、使用APP,都在使用HTTP。从1991年HTTP/0.9诞生,到1999年HTTP/1.1成为标准,HTTP协议已经陪伴我们走过了二十多年。但是,随着Web的发展,网页越来越复杂,资源越来越多,HTTP/1.1的性能瓶颈越来越明显。

2015年5月,HTTP/2(RFC 7540)正式成为IETF标准,这是HTTP协议自1999年HTTP/1.1以来的第一次重大升级。HTTP/2基于Google的SPDY协议,引入了多路复用、头部压缩、服务器推送、二进制分帧等重大改进,大幅提升了Web性能。2016年,HTTP/2开始快速普及,主流浏览器(Chrome、Firefox、Safari、Edge)都已支持,主流Web服务器(Nginx、Apache、IIS)也陆续支持。

作为一个Web开发者,了解HTTP/2是非常必要的。HTTP/2不仅能提升网站性能,还会改变我们优化Web性能的思路(很多HTTP/1.1时代的优化技巧在HTTP/2时代不再需要,甚至会适得其反)。今天就来系统地讲解HTTP/2协议详解与实践,从原理到部署,帮助你理解和使用HTTP/2。

一、HTTP/1.1的问题

在了解HTTP/2之前,我们先看看HTTP/1.1有什么问题,为什么需要升级。

1. 队头阻塞(Head-of-Line Blocking)

HTTP/1.1是基于请求-响应模型的,一个连接同一时间只能处理一个请求。虽然HTTP/1.1引入了持久连接(Keep-Alive),可以在一个TCP连接上发送多个请求,但是请求必须串行处理——必须等前一个请求的响应回来,才能发送下一个请求。

这就导致了"队头阻塞"问题:如果第一个请求很慢(比如服务器处理慢、网络延迟大),那么后面的请求都必须排队等待,即使这些请求可以很快处理完。

为了解决这个问题,浏览器通常会对同一个域名建立多个TCP连接(Chrome是6个),并行发送请求。但是,建立多个TCP连接有开销(TCP握手、慢启动),而且连接数有限制,当页面有很多资源时,还是会排队。

2. 头部冗余

HTTP/1.1的头部是文本格式,每次请求都要发送完整的头部(User-Agent、Cookie、Referer、Accept等)。很多头部字段在多次请求中是相同的(比如Cookie、User-Agent),但是每次都要重复发送,浪费带宽。

特别是Cookie,很多网站的Cookie很大(几KB甚至几十KB),每次请求都要带上,非常浪费。

3. 明文传输,解析效率低

HTTP/1.1的头部和正文都是文本格式,虽然可读性好,但是解析效率低。服务器和浏览器需要逐行解析文本,效率不高。

4. 不支持服务器推送

HTTP/1.1是严格的请求-响应模型,只能客户端请求,服务器响应。服务器不能主动推送资源给客户端。

比如,浏览器请求HTML页面,服务器返回HTML。浏览器解析HTML,发现需要CSS和JS,再发起请求获取CSS和JS。这中间有一个往返延迟(RTT)。如果服务器能在返回HTML的同时,主动把CSS和JS推送给浏览器,就能节省这个往返延迟,加快页面加载。

5. 性能优化的workaround

为了解决HTTP/1.1的性能问题,开发者们发明了很多优化技巧(workaround):

  • 域名分片(Domain Sharding):把资源分散到多个域名,突破浏览器同域名连接数限制,实现更多并行连接。
  • 资源合并(Concatenation):把多个CSS/JS文件合并成一个,减少请求数。
  • 图片精灵(CSS Sprites):把多张小图合并成一张大图,用CSS background-position显示,减少请求数。
  • 内联资源(Inlining):把小图片用Base64编码内联到CSS/HTML中,把小JS内联到HTML中,减少请求数。
  • 文件压缩(Gzip):压缩响应体,减少传输量。

这些优化技巧虽然有效,但是也带来了很多问题:增加了开发复杂度、缓存效率低(合并文件后一个小改动就要重新下载整个大文件)、资源浪费(内联的资源不能被缓存)。

HTTP/2的目标,就是从协议层面解决这些问题,让这些workaround不再需要。

二、HTTP/2的发展历程

1. SPDY的诞生

2009年,Google开始研发SPDY协议(发音"speedy"),目标是降低网页加载延迟。SPDY基于TCP,引入了多路复用、头部压缩、优先级、服务器推送等特性。

2012年,Google正式发布SPDY规范,Chrome浏览器开始支持。随后,Firefox、Opera等浏览器也支持SPDY。Nginx、Apache等服务器也陆续支持SPDY。

SPDY的效果非常显著:Google内部测试显示,SPDY能让网页加载速度提升27-60%。

2. HTTP/2的制定

SPDY的成功引起了IETF(互联网工程任务组)的关注。2012年,IETF成立了HTTPbis工作组,开始制定HTTP/2标准,并以SPDY为基础。

2015年5月,HTTP/2正式成为RFC标准(RFC 7540)。HTTP/2大量借鉴了SPDY的设计,但是也做了一些调整和改进。

2016年,Google宣布将在2016年逐步放弃SPDY,转向HTTP/2。主流浏览器和服务器也纷纷支持HTTP/2,HTTP/2开始快速普及。

3. HTTP/2 vs SPDY

HTTP/2基于SPDY,但是有一些区别:

  • HTTP/2使用HPACK头部压缩,SPDY使用zlib压缩(HPACK更安全,避免了CRIME攻击)
  • HTTP/2的优先级方案更简单
  • HTTP/2移除了SPDY中的一些特性(如SPDY的控制帧)
  • HTTP/2是IETF标准,SPDY是Google的私有协议

三、HTTP/2的核心特性

HTTP/2引入了很多重大改进,下面逐一详解。

1. 二进制分帧(Binary Framing)

HTTP/2在应用层和传输层之间增加了一个二进制分帧层。所有的消息(请求和响应)都被分割成更小的帧(Frame),采用二进制格式编码。

帧的类型:

  • HEADERS帧:携带头部信息
  • DATA帧:携带请求/响应体
  • SETTINGS帧:配置连接参数
  • WINDOW_UPDATE帧:流量控制
  • PRIORITY帧:优先级
  • RST_STREAM帧:重置流
  • PUSH_PROMISE帧:服务器推送承诺
  • PING帧:心跳检测
  • GOAWAY帧:关闭连接

二进制分帧的好处:

  • 解析效率高:二进制比文本更容易、更快解析
  • 更紧凑:二进制格式比文本更节省空间
  • 更灵活:可以方便地扩展新的帧类型
  • 多路复用的基础:分帧使得多个请求的帧可以交错传输

注意:HTTP/2的二进制分帧只影响传输层的编码,HTTP的语义(方法、状态码、头部、URI等)保持不变。开发者不需要改变使用HTTP的方式,只是底层传输变了。

2. 多路复用(Multiplexing)

多路复用是HTTP/2最重要的特性。在HTTP/2中,一个TCP连接上可以同时有多个"流"(Stream),每个流对应一个请求-响应。不同流的帧可以交错传输,不需要等待前一个请求完成。

这就彻底解决了HTTP/1.1的队头阻塞问题。一个连接上可以并行处理多个请求,不需要建立多个TCP连接,也不需要排队等待。

多路复用的好处:

  • 解决队头阻塞:请求不再排队
  • 减少连接数:一个连接就能并行处理多个请求,减少TCP握手和慢启动开销
  • 降低延迟:请求可以立即发送,不需要等待
  • 节省资源:减少服务器的连接数和内存占用

注意:HTTP/2解决了应用层的队头阻塞,但是TCP层仍然有队头阻塞(一个TCP包丢失会导致整个连接等待重传)。这是HTTP/2基于TCP的固有问题,HTTP/3(基于QUIC/UDP)正在解决这个问题。

3. 头部压缩(HPACK)

HTTP/2使用HPACK算法压缩HTTP头部,减少头部的传输量。

HPACK的工作原理:

  • 静态表:预定义了61个常见头部字段(如:method、:path、user-agent、cookie等),用索引表示,不需要重复传输完整字段名。
  • 动态表:在连接过程中,新出现的头部字段会被加入动态表,后续相同的头部可以用索引引用。
  • 霍夫曼编码:对头部值进行霍夫曼编码,进一步压缩。

头部压缩的好处:

  • 减少重复头部的传输(如Cookie、User-Agent每次请求都相同)
  • 节省带宽,加快传输速度
  • 特别适合移动网络(带宽有限、延迟高)

HPACK比SPDY的zlib压缩更安全,避免了CRIME攻击(一种通过压缩长度变化推断加密内容的攻击)。

4. 服务器推送(Server Push)

HTTP/2支持服务器主动推送资源给客户端,不需要客户端请求。

工作原理:

  1. 客户端请求HTML页面
  2. 服务器返回HTML的同时,通过PUSH_PROMISE帧告诉客户端:"我要给你推送CSS和JS"
  3. 服务器主动把CSS和JS推送给客户端
  4. 客户端解析HTML时,发现需要CSS和JS,发现已经被推送了,直接使用,不需要再发起请求

服务器推送的好处:

  • 减少往返延迟(RTT):客户端不需要等解析HTML后再请求CSS/JS
  • 加快页面加载:关键资源可以提前到达
  • 特别适合首屏关键资源(CSS、关键JS、首屏图片)

服务器推送的注意事项:

  • 不要推送已经被客户端缓存的资源(浪费带宽)
  • 推送关键资源即可,不要推送所有资源
  • 推送的资源要和请求的页面相关
  • 浏览器可以拒绝推送(通过RST_STREAM帧)
  • 服务器推送的实现和配置因服务器而异

注意:服务器推送在实际应用中效果参差不齐,有时候甚至会降低性能(如推送了缓存的资源)。需要谨慎使用,做好测试。2019年Chrome甚至宣布将移除服务器推送支持,因为实际收益有限。

5. 流量控制(Flow Control)

HTTP/2支持流量控制,防止发送方发送太快,接收方处理不过来。

流量控制是基于每个流和整个连接的。接收方通过WINDOW_UPDATE帧告诉发送方自己还能接收多少数据。发送方不能超过接收方通告的窗口大小。

流量控制的好处:

  • 防止接收方被淹没
  • 支持不同速度的客户端
  • 可以给不同的流分配不同的流量

6. 优先级(Priority)

HTTP/2支持给每个流设置优先级,告诉服务器哪些请求更重要,应该优先处理。

比如,浏览器请求HTML、CSS、JS、图片时,可以给HTML和CSS设置高优先级,给图片设置低优先级。服务器会优先处理高优先级的请求,加快关键资源的加载。

优先级可以通过PRIORITY帧设置,也可以在HEADERS帧中携带优先级信息。

优先级的好处:

  • 关键资源优先加载,加快首屏渲染
  • 优化用户体验(先看到重要内容)

7. 重置流(Stream Reset)

HTTP/2支持重置一个流,而不需要关闭整个连接。

在HTTP/1.1中,如果想取消一个请求,只能关闭整个TCP连接,然后重新建立连接,开销很大。而HTTP/2可以通过RST_STREAM帧重置单个流,其他流不受影响,连接继续使用。

这对于取消大文件下载、用户跳转页面等场景很有用。

8. 连接设置(SETTINGS)

HTTP/2在连接建立时,通过SETTINGS帧协商连接参数,如:

  • 最大并发流数
  • 初始窗口大小
  • 最大帧大小
  • 头部表大小

双方可以通过SETTINGS帧调整这些参数,优化连接性能。

四、HTTP/2 vs HTTP/1.1 对比

对比项HTTP/1.1HTTP/2
传输格式文本二进制
多路复用不支持(串行请求)支持(一个连接并行多请求)
队头阻塞有(应用层)无(应用层,TCP层仍有)
头部压缩无(Gzip只压缩body)HPACK头部压缩
服务器推送不支持支持
流量控制无(TCP层)有(应用层+TCP层)
优先级支持
加密可选(HTTP/HTTPS)主流浏览器只支持HTTPS(h2)
连接数多连接(同域名6个)单连接(多路复用)
性能优化需要域名分片、资源合并、图片精灵等不需要这些workaround

HTTP/2的性能提升主要来自:

  1. 多路复用解决队头阻塞,减少连接数和延迟
  2. 头部压缩减少传输量
  3. 服务器推送减少往返延迟
  4. 优先级优化关键资源加载

五、浏览器和服务器支持情况

1. 浏览器支持

2016年,主流浏览器都已支持HTTP/2:

  • Chrome:40+支持HTTP/2(2015年)
  • Firefox:36+支持HTTP/2(2015年)
  • Safari:9+支持HTTP/2(2015年,OS X 10.11+)
  • Edge:12+支持HTTP/2(2015年,Windows 10)
  • IE:IE 11不支持HTTP/2(IE已经被Edge取代)

注意:主流浏览器只支持基于TLS的HTTP/2(即h2,HTTPS),不支持明文HTTP/2(h2c)。所以,要使用HTTP/2,网站必须启用HTTPS。

2. 服务器支持

2016年,主流Web服务器也陆续支持HTTP/2:

  • Nginx:1.9.5+支持HTTP/2(2015年9月),1.10+稳定支持
  • Apache:2.4.17+支持HTTP/2(mod_http2模块,2015年)
  • IIS:Windows 10/Server 2016的IIS 10支持HTTP/2
  • LiteSpeed:5.0+支持HTTP/2
  • Caddy:原生支持HTTP/2,自动HTTPS

3. CDN支持

主流CDN也支持HTTP/2:

  • CloudFlare:免费支持HTTP/2
  • 阿里云CDN:支持HTTP/2
  • 腾讯云CDN:支持HTTP/2
  • 七牛云:支持HTTP/2
  • 又拍云:支持HTTP/2

六、Nginx配置HTTP/2

Nginx是最流行的Web服务器之一,下面介绍如何在Nginx中配置HTTP/2。

1. 前提条件

  • Nginx版本1.9.5+(推荐1.10+稳定版)
  • Nginx编译时包含httpv2module模块(默认包含)
  • OpenSSL版本1.0.2+(支持ALPN,HTTP/2需要ALPN协商)
  • 网站已启用HTTPS(浏览器只支持HTTPS的HTTP/2)

检查Nginx是否支持HTTP/2:

nginx -V 2>&1 | grep http_v2
# 如果输出包含--with-http_v2_module,说明支持

检查OpenSSL版本:

openssl version
# 需要1.0.2+,支持ALPN

2. 基本配置

在Nginx的server块中,listen指令加上http2参数:

server {
    # 同时支持HTTP/1.1和HTTP/2
    listen 443 ssl http2;
    server_name example.com;

    # SSL证书配置
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # SSL协议(HTTP/2需要TLS 1.2+)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
    ssl_prefer_server_ciphers on;

    # 根目录和首页
    root /var/www/example.com;
    index index.html;

    # 其他配置...
}

HTTP/80端口可以重定向到HTTPS:

server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

3. HTTP/2相关配置

server {
    listen 443 ssl http2;
    server_name example.com;

    # ... SSL配置 ...

    # HTTP/2最大并发流数(默认128)
    http2_max_concurrent_streams 128;

    # HTTP/2头部表大小(默认4096)
    http2_recv_buffer_size 16k;

    # 服务器推送配置(Nginx 1.13.9+支持)
    # 当请求/index.html时,推送/style.css和/app.js
    location = /index.html {
        http2_push /style.css;
        http2_push /app.js;
    }

    # 静态资源缓存
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

4. 验证HTTP/2是否生效

方法1:浏览器开发者工具

  • Chrome/Firefox按F12打开开发者工具
  • Network面板,刷新页面
  • 查看Protocol列,如果显示h2,说明使用了HTTP/2
  • 如果没有Protocol列,右键表头勾选Protocol

方法2:命令行测试

# 使用curl测试(需要curl 7.43+,支持--http2)
curl -I --http2 https://example.com
# 如果响应头包含HTTP/2 200,说明支持HTTP/2

# 使用openssl测试ALPN
openssl s_client -alpn h2 -connect example.com:443 -servername example.com </dev/null 2>&1 | grep ALPN
# 如果输出ALPN protocol: h2,说明支持HTTP/2

方法3:在线工具

  • https://tools.keycdn.com/http2-test
  • https://http2.pro/

七、Apache配置HTTP/2

Apache 2.4.17+通过mod_http2模块支持HTTP/2。

1. 启用模块

# 启用http2模块
a2enmod http2

# 重启Apache
systemctl restart apache2

2. 配置

<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/example.com

    # 启用HTTP/2
    Protocols h2 http/1.1

    # SSL配置
    SSLEngine on
    SSLCertificateFile /path/to/cert.pem
    SSLCertificateKeyFile /path/to/key.pem

    # SSL协议
    SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    SSLHonorCipherOrder on

    # 服务器推送(Apache 2.4.19+)
    <Location /index.html>
        H2PushResource /style.css
        H2PushResource /app.js
    </Location>
</VirtualHost>

八、HTTP/2性能优化实践

1. HTTP/2时代不再需要的优化

HTTP/2解决了HTTP/1.1的很多问题,一些HTTP/1.1时代的优化技巧在HTTP/2时代不再需要,甚至会适得其反:

  • 域名分片(Domain Sharding):HTTP/2一个连接就能多路复用,不需要多个域名。域名分片反而会建立多个TCP连接,增加开销,而且每个连接的头部压缩表是独立的,降低压缩效率。HTTP/2时代应该把资源合并到同一个域名。
  • 资源合并(Concatenation):HTTP/2多路复用,多个小文件可以并行加载,不需要合并成大文件。合并大文件反而会降低缓存效率(一个小改动就要重新下载整个大文件),而且大文件的优先级不好控制。HTTP/2时代可以适当拆分资源,保持合理的文件大小。
  • 图片精灵(CSS Sprites):HTTP/2多路复用,多张小图可以并行加载,不需要合并成精灵图。精灵图会降低缓存效率,而且修改麻烦。HTTP/2时代可以使用独立的小图片,或者用SVG图标、iconfont。
  • 内联资源(Inlining):HTTP/2服务器推送可以替代内联,而且推送的资源可以被缓存。内联的资源不能被缓存,增加了HTML的大小。HTTP/2时代优先使用服务器推送,而不是内联。

注意:这些优化不是完全不能用,而是不再是必须的。在某些特定场景下(如极老旧的浏览器、特殊的性能需求),可能还需要。但是对于现代浏览器,优先利用HTTP/2的特性。

2. HTTP/2时代的优化重点

HTTP/2时代,性能优化的重点转向:

  • 启用HTTPS:HTTP/2需要HTTPS,而且HTTPS也是趋势。使用Let's Encrypt等免费证书。
  • 优化TLS:使用TLS 1.2+,启用OCSP Stapling,会话恢复,TLS False Start,减少TLS握手开销。
  • 合理使用服务器推送:推送首屏关键资源(CSS、关键JS),不要推送缓存的资源,不要推送所有资源。
  • 优化缓存策略:合理设置Cache-Control,利用浏览器缓存,减少重复请求。
  • 图片优化:使用WebP等现代图片格式,响应式图片,懒加载,压缩图片。
  • 减少重定向:重定向会增加往返延迟,尽量避免。
  • 使用CDN:CDN能加速静态资源,支持HTTP/2的CDN效果更好。
  • 关键渲染路径优化:优化首屏渲染,内联关键CSS(小范围),异步加载非关键JS。
  • Gzip/Brotli压缩:压缩响应体,减少传输量。Brotli比Gzip压缩率更高。

3. 渐进式部署

部署HTTP/2时,可以渐进式进行:

  1. 先启用HTTPS(HTTP/2的前提)
  2. 升级服务器到支持HTTP/2的版本
  3. 配置HTTP/2,测试兼容性
  4. 逐步移除HTTP/1.1时代的优化(域名分片、资源合并等),观察性能变化
  5. 尝试服务器推送等新特性
  6. 监控性能,持续优化

注意:HTTP/2和HTTP/1.1可以共存,Nginx的listen 443 ssl http2会同时支持两种协议,浏览器会自动协商。不需要担心旧浏览器不兼容。

九、迁移注意事项

1. HTTPS是前提

主流浏览器只支持基于TLS的HTTP/2(h2),所以网站必须启用HTTPS。如果网站还没有HTTPS,需要先配置HTTPS。

  • 可以使用Let's Encrypt免费证书
  • 确保所有资源都使用HTTPS(避免混合内容)
  • 配置301重定向,把HTTP跳转到HTTPS

2. 兼容性

  • 现代浏览器都支持HTTP/2,旧浏览器(如IE 11及以下)不支持
  • 服务器会自动协商,不支持HTTP/2的浏览器会使用HTTP/1.1
  • 不需要为旧浏览器做特殊处理

3. 性能不一定立即提升

HTTP/2不一定能让所有网站都立即变快,特别是:

  • 网站资源很少的(几个请求),HTTP/2优势不明显
  • 服务器配置不当的(如TLS配置差、没有keepalive)
  • 网络环境差的(高延迟、高丢包)
  • 没有移除HTTP/1.1优化的(域名分片等反而会降低HTTP/2性能)

需要做好测试和监控,根据实际情况优化。

4. 服务器资源

HTTP/2的多路复用会让一个连接处理更多请求,服务器的CPU和内存占用可能会增加。需要确保服务器有足够的资源,必要时调整worker进程数和连接数。

5. 调试工具

  • Chrome/Firefox开发者工具的Network面板可以查看Protocol列
  • Chrome的chrome://net-internals/#http2可以查看HTTP/2连接详情
  • curl --http2可以命令行测试
  • 在线工具:https://tools.keycdn.com/http2-test

十、总结

HTTP/2是HTTP协议自1999年HTTP/1.1以来的第一次重大升级,基于Google的SPDY协议,2015年成为RFC标准,2016年开始快速普及。

HTTP/2的核心特性:

  1. 二进制分帧:二进制格式,解析效率高,是多路复用的基础
  2. 多路复用:一个TCP连接并行处理多个请求,解决队头阻塞,减少连接数
  3. 头部压缩(HPACK):压缩HTTP头部,减少重复传输,节省带宽
  4. 服务器推送:服务器主动推送资源,减少往返延迟
  5. 流量控制:防止发送方淹没接收方
  6. 优先级:关键资源优先加载
  7. 重置流:取消单个请求而不关闭连接

HTTP/2解决了HTTP/1.1的队头阻塞、头部冗余、不支持推送等问题,大幅提升了Web性能。同时,HTTP/2也改变了Web性能优化的思路:域名分片、资源合并、图片精灵、内联资源等HTTP/1.1时代的优化技巧不再需要,甚至会适得其反。

部署HTTP/2需要:

  • 启用HTTPS(浏览器只支持HTTPS的HTTP/2)
  • 升级服务器到支持HTTP/2的版本(Nginx 1.9.5+、Apache 2.4.17+)
  • 配置HTTP/2(listen加上http2参数)
  • 逐步移除HTTP/1.1时代的优化
  • 合理使用服务器推送
  • 做好测试和监控

HTTP/2是Web的未来,2016年已经有越来越多的网站支持HTTP/2。作为Web开发者,了解和使用HTTP/2是必要的。希望本文能帮助你理解HTTP/2,部署HTTP/2,让你的网站更快、更好。

最后,HTTP/2不是终点,HTTP/3(基于QUIC/UDP)已经在制定中,将解决TCP层的队头阻塞问题,进一步提升Web性能。技术在不断进步,我们也要不断学习,跟上时代的步伐。