Accelerate networking with HTTP/3 and QUIC
System & Services 进阶 22m

使用 HTTP/3 和 QUIC 加速网络通信

Accelerate networking with HTTP/3 and QUIC

2021年6月11日

在 Apple 官方观看视频

一句话判断

苹果在 iOS 15 / macOS 12 中默认启用了 HTTP/3 —— 你什么都不用改,URLSession 自动走 QUIC 协议,在高丢包和高延迟网络下连接建立速度提升明显,但前提是你的服务端也要支持。

这场 Session 讲了什么

Session 讲解了 HTTP/3 和 QUIC 协议在苹果平台上的实现和优化。HTTP/3 是 HTTP 协议的最新版本,底层传输层从 TCP 切换到 QUIC(基于 UDP)。主要优势包括:更快的连接建立(0-RTT 恢复)、更好的多路复用(没有 TCP 的队头阻塞问题)、以及连接迁移(网络切换时不断开)。

苹果在 URLSession 中默认支持了 HTTP/3。开发者不需要修改任何代码,只要服务端支持 HTTP/3(通过 Alt-Svc header 声明),URLSession 会自动升级。还介绍了 Network.framework 对 QUIC 的原生支持,适合需要更底层控制的应用。

Session 还讨论了如何在服务端配置 HTTP/3、如何调试 QUIC 连接、以及 HTTP/3 对现有网络优化策略的影响。

值得深挖的点

0-RTT 连接恢复的工程细节。QUIC 的 0-RTT 允许客户端在重新连接时携带上一次会话的加密参数,第一个包就带数据,省去了完整的 TLS 握手。在弱网环境下(如 3G/4G 边缘),连接建立时间从 2-3 个 RTT 缩短到 0-1 个 RTT。但 0-RTT 有重放攻击风险,不适合非幂等请求(如支付提交)。URLSession 会自动判断哪些请求可以用 0-RTT。

连接迁移的实际意义。QUIC 用 Connection ID 而不是四元组(源 IP + 源端口 + 目标 IP + 目标端口)标识连接。当用户从 Wi-Fi 切到蜂窝网络时,IP 地址变了但 Connection ID 不变,连接可以无缝继续。在 TCP 下这种情况会断连重连。对于直播、视频通话等长连接场景,这是巨大的体验提升。

代码片段

URLSession 自动使用 HTTP/3(无需代码改动)

import Foundation

// URLSession 默认支持 HTTP/3,无需额外配置
// 只要服务端通过 Alt-Svc header 声明支持 HTTP/3
let session = URLSession(configuration: .default)
let url = URL(string: "https://api.example.com/data")!

let task = session.dataTask(with: url) { data, response, error in
    if let httpResponse = response as? HTTPURLResponse {
        // 检查实际使用的协议版本
        print("协议版本: \(http httpResponse.url)")
    }
}
task.resume()

显式启用 HTTP/3 的 URLSession 配置

import Foundation

func createHTTP3Session() -> URLSession {
    let config = URLSessionConfiguration.default
    // 显式请求 HTTP/3(如果服务端不支持则回退到 HTTP/2)
    config.httpMaximumConnectionsPerHost = 10
    // 在 iOS 15+,URLSession 会自动尝试 HTTP/3
    return URLSession(configuration: config)
}

使用 Network.framework 建立 QUIC 连接

import Network

func createQUICConnection(to host: String, port: Int) {
    let endpoint = NWEndpoint.hostPort(
        host: NWEndpoint.Host(host),
        port: NWEndpoint.Port(rawValue: UInt16(port))!
    )
    // 创建 QUIC 连接
    let parameters = NWParameters.quic(alpn: ["h3"])
    let connection = NWConnection(to: endpoint, using: parameters)

    connection.stateUpdateHandler = { state in
        switch state {
        case .ready:
            print("QUIC 连接建立成功")
        case .failed(let error):
            print("QUIC 连接失败: \(error)")
        case .waiting(let error):
            print("等待连接: \(error)")
        default:
            break
        }
    }
    connection.start(queue: .main)
}

最佳实践

  1. 服务端先配好 HTTP/3 再考虑客户端优化。大多数 CDN(Cloudflare、Akamai、Fastly)已经支持 HTTP/3,开启即可。自建服务端推荐用 nginx 1.25+ 或 Cloudflare quiche 库。
  2. 不要假设所有请求都走 HTTP/3。部分网络环境(企业防火墙、运营商 NAT)会屏蔽 UDP 流量导致 QUIC 不可用。URLSession 会自动回退到 HTTP/2,你的逻辑要兼容两种协议。
  3. 用 Network Instruments 的 QUIC 模板调试。Xcode 13 的 Instruments 新增了 QUIC 连接追踪,可以看到握手时间、0-RTT 命中率、丢包率等指标。

还有什么值得关注

  • Safari 在 iOS 15 / macOS 12 中默认启用 HTTP/3,Web 开发者无需额外操作。
  • NWConnection 的 QUIC 支持双向流(Bidirectional Stream),适合实时通信场景。
  • 苹果建议用 dnsOverHTTPSdnsOverTLS 配合 HTTP/3,减少 DNS 泄露。
WWDC 2021