飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • HTTP 基础

    • 认识HTTP协议与应用层定位
    • HTTP消息格式与报文结构
    • HTTP请求方法与幂等性
    • HTTP状态码详解
  • 连接与缓存

    • HTTP持久连接与版本演进
    • HTTP缓存机制
  • 状态与协商

    • Cookie与Session状态管理
    • HTTP重定向与内容协商
    • HTTP条件请求与范围请求
  • 安全与加密

    • HTTP认证机制
    • HTTPS与TLS握手
  • 协议演进

    • HTTP2核心特性
    • HTTP3与QUIC
  • 架构与实战

    • HTTP代理服务器与Web缓存
    • HTTP常见攻击与防御
    • HTTP实践工具与抓包分析

答案:HTTP2核心特性

HTTP/2 的多路复用解决了 HTTP 层的队头阻塞,为什么 TCP 层还会阻塞?如果 TCP 连接上某个 Stream 的数据包丢失,为什么其他 Stream 也要等待?

答案:

HTTP/2 的多路复用确实解决了应用层的队头阻塞——在 HTTP/1.1 中,浏览器对同一域名只能开 6~8 个 TCP 连接,如果第 1 个请求的 JS 文件很大,后面的 CSS 请求只能排队等待。HTTP/2 把所有请求放在一条 TCP 连接上,用 Stream ID 区分,理论上可以并行传输。

但 TCP 是可靠、按序传输的协议。假设飞翔官网的 HTTP/2 连接上同时传输 3 个 Stream:

  • Stream 1:首页 HTML(优先级高)
  • Stream 3:logo.png
  • Stream 5:app.js

如果 Stream 3 的某个 TCP 数据包(比如序列号 1000~1499)在传输中丢失了,TCP 的滑动窗口机制会要求发送方重传这个包。在丢失的包被成功重传并确认之前,TCP 不会把后续任何数据(包括 Stream 1 和 Stream 5 的数据)交付给应用层,即使这些数据已经完好到达接收端缓冲区。

这就是TCP 层的队头阻塞——TCP 不知道上层 HTTP/2 的 Stream 概念,它只看到一个连续的字节流,必须保证字节流的完整和有序。

发送端:
Stream1: [A1][A2][A3]...
Stream3: [B1][B2][B3][B4]...
Stream5: [C1][C2][C3]...

TCP 层(混成一个字节流):
[A1][B1][A2][B2][C1][B3]...[B4丢失]...[A3][C2]...

接收端:
B4 丢失 → TCP 暂停交付 → A3、C2 已在缓冲区但无法交给 HTTP/2
→ 所有 Stream 都卡住,等待 B4 重传

这也是 HTTP/3 改用 QUIC(基于 UDP)的核心动机——QUIC 在传输层就实现了 Stream 隔离,一个 Stream 的丢包不会影响其他 Stream。


空少想给飞翔官网启用 HTTP/2,但担心老客户端不支持。HTTP/2 的协商机制是什么?不支持 HTTP/2 的客户端会怎样降级?

答案:

HTTP/2 的协商机制是完全向后兼容的,老客户端会自动降级到 HTTP/1.1,无需空少担心。

HTTPS 场景(主流方式)—— ALPN(Application-Layer Protocol Negotiation):

ALPN 是 TLS 握手扩展,客户端在 ClientHello 中发送自己支持的协议列表(如 h2, http/1.1),服务器从中选择最优的回复。这是目前主流浏览器启用 HTTP/2 的标准方式。

# 用 OpenSSL 查看飞翔官网的 ALPN 协商
echo | openssl s_client -alpn h2,http/1.1 -connect www.feixiang.net:443 | grep ALPN
# 输出示例:
# ALPN protocol: h2

HTTP 场景(较少见)—— Upgrade 机制:

客户端先发送 HTTP/1.1 请求,携带 Upgrade: h2c 头,服务器如果支持则返回 101 Switching Protocols,双方切换到 HTTP/2。但主流浏览器不支持 h2c(HTTP/2 over cleartext),只支持 h2(HTTP/2 over TLS)。

不支持 HTTP/2 的客户端会怎样?

  1. 老浏览器(IE11 及更早):TLS 握手时不发送 ALPN 扩展,服务器默认选择 HTTP/1.1
  2. curl 老版本:默认 HTTP/1.1,需显式加 --http2 才尝试
  3. 某些 API 客户端:如果代码写死了 HTTP/1.1,完全不受影响
# 强制使用 HTTP/1.1 访问(模拟老客户端)
curl --http1.1 -I https://www.feixiang.net
# HTTP/1.1 200 OK

# 显式请求 HTTP/2
curl --http2 -I https://www.feixiang.net
# HTTP/2 200 OK

空少(运维工程师)在飞翔公司的部署策略是:Nginx 同时监听 HTTP/1.1 和 HTTP/2,listen 443 ssl http2; 这一行就同时支持两种协议,ALPN 自动协商,老客户端零感知降级。


HTTP/2 要求强制 HTTPS 吗?实际上主流浏览器(Chrome、Firefox、Safari)对 HTTP/2 的实现有什么限制?这对飞翔官网的部署策略有什么影响?

答案:

HTTP/2 协议本身不要求 HTTPS。 RFC 7540 明确规定了两种实现:

  • h2:HTTP/2 over TLS(基于 ALPN 协商)
  • h2c:HTTP/2 over cleartext(基于 HTTP/1.1 Upgrade 机制)

但主流浏览器实际上强制要求 HTTPS:

浏览器HTTP/2 支持条件
Chrome仅支持 h2(TLS + ALPN),拒绝 h2c
Firefox仅支持 h2,拒绝 h2c
Safari仅支持 h2,拒绝 h2c
Edge仅支持 h2,拒绝 h2c

这意味着:虽然理论上你可以用 curl --http2-prior-knowledge http://example.com 直接访问 h2c,但真实用户使用的浏览器全部要求 HTTPS。从实际部署角度,HTTP/2 ≈ HTTPS。

对飞翔官网部署策略的影响:

  1. 必须先完成全站 HTTPS 改造:如果还有 HTTP 页面,启用 HTTP/2 对这些用户没有意义(他们会回退到 HTTP/1.1)

  2. TLS 版本要求:HTTP/2 的 ALPN 需要 TLS 1.2+,旧版 OpenSSL(< 1.0.1)不支持,服务器需要升级

  3. 证书配置优化:HTTP/2 多路复用减少了连接数,但 TLS 握手成本还在。翼王要求飞翔官网启用 OCSP Stapling 和 Session Ticket 复用,减少 TLS 握手开销:

# 飞翔官网 Nginx HTTP/2 配置(空少维护)
server {
    listen 443 ssl http2;
    server_name www.feixiang.net;
    
    ssl_certificate /etc/nginx/ssl/feixiang.crt;
    ssl_certificate_key /etc/nginx/ssl/feixiang.key;
    
    # TLS 优化
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE+AESGCM:ECDHE+CHACHA20;
    ssl_prefer_server_ciphers on;
    
    # OCSP Stapling(减少证书验证延迟)
    ssl_stapling on;
    ssl_stapling_verify on;
    
    # Session 复用
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets on;
    
    # HTTP/2 特定优化
    http2_push_preload on;  # 服务端推送(谨慎使用)
}
  1. 监控与灰度:空少先用 CDN 的灰度功能,对 10% 流量启用 HTTP/2,监控错误率和延迟变化,确认无误后再全量开启。

靓晴(前端负责人)还建议:启用 HTTP/2 后,不要再做域名分片(sharding)。HTTP/1.1 时代把静态资源拆到 cdn1.feixiang.net、cdn2.feixiang.net 是为了突破 6 连接限制,HTTP/2 下单连接多路复用更高效,域名分片反而增加不必要的 TLS 握手开销。