HTTP1
概述
HTTP/0.9局限性(1989)
- 仅支持
GET方法,无状态码、无头部字段,每次请求需重新建立TCP连接
HTTP/1.0性能瓶颈(1996)
- 默认短连接导致频繁三次握手,且无复用机制,造成高延迟和资源浪费
- 关键需求:降低网络延迟、减少重复头部传输、支持复杂资源类型(如图片和脚本)
HTTP/1.1 革新(1997)
- 引入 持久连接(
Keep-Alive),默认复用TCP连接处理多个请求,并通过以下改进提升性能:- 管道机制(
Pipelining):允许客户端连续发送多个请求(实际因队头阻塞问题被禁用) - 分块传输编码(
Chunked Encoding):支持流式传输大文件 - 强制
Host头部:支持虚拟主机托管
- 管道机制(
协议内容
请求报文结构
|
1 2 3 4 5 6 7 |
GET /index.html HTTP/1.1 ← 请求行(方法 + URI + 版本) Host: example.com ← 请求头(键值对元数据) User-Agent: Mozilla/5.0 Accept: text/html Connection: keep-alive ← 控制持久连接 (空行) ← 分隔头部与正文 [请求正文] ← GET 请求通常为空 |
响应报文结构
|
1 2 3 4 5 6 |
HTTP/1.1 200 OK ← 状态行(版本 + 状态码 + 描述) Content-Type: text/html ← 响应头(资源类型、缓存策略等) Content-Length: 1024 Server: Apache/2.4 (空行) <html>...</html> ← 响应正文 |
关键头部字段
| 字段 | 作用 |
Host |
指定目标服务器域名(HTTP/1.1 强制要求) |
Connection |
keep-alive 表示保持连接,close 表示关闭 |
Content-Length |
实体正文长度(单位:字节) |
Content-Type |
MIME 类型(如 text/html; charset=utf-8) |
Cache-Control |
控制缓存行为(如 max-age=3600) |
支持的方法
GET
- 作用
- 请求指定资源(如
HTML页面、图片),参数通过URL传递(如?id=123)
- 请求指定资源(如
- 特点
- 安全(不修改资源)、幂等(多次请求结果一致)、可缓存
- 场景
- 加载网页、获取
API数据
- 加载网页、获取
|
1 |
GET /index.html HTTP/1.0 |
POST
- 作用
- 向服务器提交数据(如表单内容),请求体携带数据(如
JSON、文件)
- 向服务器提交数据(如表单内容),请求体携带数据(如
- 特点
- 非安全(可能修改资源状态)、非幂等(重复提交可能产生不同结果)
- 场景
- 用户注册、文件上传
|
1 2 3 4 5 |
POST /submit-form HTTP/1.0 Content-Type: application/x-www-form-urlencoded Content-Length: 27 username=John&password=123 |
HEAD
- 作用
- 与
GET类似,但仅返回响应头(不包含实体正文)
- 与
- 特点
- 轻量级请求,用于检查资源是否存在或是否更新(如
Last-Modified时间戳)
- 轻量级请求,用于检查资源是否存在或是否更新(如
- 场景
- 验证链接有效性、资源缓存状态检查
|
1 |
HEAD /status HTTP/1.0 |
PUT
- 作用
- 全量更新资源,客户端需提供完整数据
- 特点
- 幂等(多次更新结果一致),但可能覆盖其他用户修改
- 场景
- 用户信息全量更新
|
1 2 3 |
PUT /users/123 HTTP/1.1 Content-Type: application/json {"name": "John", "age": 30} |
DELETE
- 作用
- 删除指定资源
- 特点
- 幂等(多次删除同一资源效果相同),但直接修改服务器状态
- 场景
- 删除文章、用户账户
|
1 |
DELETE /articles/456 HTTP/1.1 |
OPTIONS
- 作用
- 查询服务器支持的请求方法或跨域权限(
CORS预检请求)
- 查询服务器支持的请求方法或跨域权限(
- 特点
- 用于
API兼容性检查或安全策略验证
- 用于
- 场景
- 跨域请求前的预检
|
1 |
OPTIONS /api/data HTTP/1.1 |
TRACE
- 作用
- 回显客户端请求,用于调试网络路径
- 特点
- 因安全风险(如
XST攻击)通常被禁用
- 因安全风险(如
- 场景
- 诊断代理服务器行为
|
1 |
TRACE /debug HTTP/1.1 |
CONNECT
- 作用
- 建立代理隧道(如
HTTPS加密通信)
- 建立代理隧道(如
- 特点
- 由代理服务器处理,不直接暴露给业务层
- 场景
- 通过代理访问
HTTPS网站
- 通过代理访问
|
1 |
CONNECT example.com:443 HTTP/1.1 |
PATCH
- 扩展方法(非
HTTP/1.1原生) - 作用
- 局部更新资源(仅修改部分字段)
- 特点
- 非幂等(多次更新可能产生不同结果),需定义数据格式(如
JSON Patch)
- 非幂等(多次更新可能产生不同结果),需定义数据格式(如
- 场景
- 修改用户昵称或部分配置
|
1 2 3 |
PATCH /users/123 HTTP/1.1 Content-Type: application/json-patch+json [{"op": "replace", "path": "/name", "value": "Jane"}] |
对比
PUT与POST的误用PUT用于全量更新(客户端控制资源标识)POST用于创建资源(服务器分配标识)
持久连接(Keep-Alive)
概述
- 在
HTTP/1.0中,每次请求都需要建立新的TCP连接,导致 三次握手和四次挥手的频繁开销,尤其对于含多个资源(如CSS、JS、图片)的网页,加载性能极差 - 持久连接(
Keep-Alive) 的提出正是为了复用TCP连接,允许 同一连接处理多个请求/响应,从而减少延迟和资源消耗
工作原理与协议定义
HTTP/1.0:非默认支持,需显式通过头部协商:
|
1 2 |
Connection: Keep-Alive // 客户端请求 Connection: Keep-Alive // 服务端响应 |
HTTP/1.1:默认开启持久连接,若需关闭需显式声明:
|
1 |
Connection: close |
连接复用流程
- 客户端发送首个请求,建立
TCP连接 - 服务端响应后,保持连接开放(而非关闭)
- 客户端在 同一连接 上发送后续请求,无需重复握手
- 连接空闲超时(如
Nginx默认75秒)或达到最大请求数后关闭
与 TCP Keepalive 的区别
| 特性 | HTTP Keep-Alive | TCP Keepalive |
| 作用层级 | 应用层(HTTP 协议) | 传输层(TCP 协议) |
| 目的 | 复用 TCP 连接处理多个 HTTP 请求 | 检测连接存活状态,防止半开连接 |
| 实现方式 | 通过 Connection 头部协商 |
内核参数控制(如 tcp_keepalive_time) |
| 触发条件 | HTTP 请求完成后保持连接 | 连接空闲后发送心跳包 |
| 典型配置 | Nginx 的 keepalive_timeout 75s; |
Linux 系统的 /proc/sys/net/ipv4/ 参数 |
实际配置示例(Nginx)
|
1 2 3 4 5 6 7 8 9 10 11 |
http { keepalive_timeout 75s; // 空闲超时时间 keepalive_requests 100; // 单连接最大请求数 server { listen 80; location / { proxy_http_version 1.1; // 启用 HTTP/1.1 proxy_set_header Connection ""; // 强制保持连接 } } } |
相关库
cpp-httplib
- 单头文件库,支持同步客户端/服务端
- 适合快速原型开发
- 客户端示例代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <httplib.h> int main() { httplib::Client cli("http://example.com"); // 发送 GET 请求 auto res = cli.Get("/api/data"); if (res && res->status == 200) { std::cout << "响应内容:" << res->body << std::endl; } // 发送 POST 请求(JSON 数据) httplib::Headers headers = {{"Content-Type", "application/json"}}; std::string body = R"({"key": "value"})"; auto res_post = cli.Post("/submit", headers, body, "application/json"); } |
- 服务端示例代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <httplib.h> int main() { httplib::Server svr; // 处理 GET 请求 svr.Get("/hello", [](const httplib::Request& req, httplib::Response& res) { res.set_content("Hello, HTTP/1.1!", "text/plain"); }); // 处理 POST 请求 svr.Post("/data", [](const httplib::Request& req, httplib::Response& res) { std::cout << "收到数据:" << req.body << std::endl; res.status = 200; }); svr.listen("0.0.0.0", 8080); } |
libcurl
- 多协议支持(
HTTP/HTTPS/FTP),异步请求 - 适合高性能客户端
Boost.Beast
- 基于
Boost.Asio,支持HTTP/WebSocket,高度可扩展 - 适合企业级服务端开发
HTTP1的问题与解决方案
核心瓶颈
- 队头阻塞(
HOL Blocking)- 管道机制因响应顺序依赖导致性能下降
- 头部冗余
- 每次请求携带重复头部(如
User-Agent),浪费带宽
- 每次请求携带重复头部(如
- 连接数限制
- 浏览器对同一域名限制并发连接数(通常
6-8个),影响资源加载速度
- 浏览器对同一域名限制并发连接数(通常
优化方案
- 域名分片(
Domain Sharding)- 将资源分散到多个子域名突破连接限制
- 资源合并
- 合并
CSS/JS文件、使用雪碧图减少请求次数
- 合并
- 协议演进
- 通过
SPDY协议过渡到HTTP/2,引入多路复用和头部压缩
- 通过
HTTP/1.1 管道化(Pipelining)的瓶颈
- 问题
- 请求必须按顺序响应,队头阻塞(
Head-of-Line Blocking)导致性能下降
- 请求必须按顺序响应,队头阻塞(
- 解决方案
- 使用
HTTP/2多路复用或HTTP/3 QUIC协议规避TCP层阻塞
- 使用
HTTP2
概述
HTTP/1.1的瓶颈
- 队头阻塞
- 单个
TCP连接中请求必须按顺序处理,前序请求延迟会阻塞后续请求,导致页面加载效率低下
- 单个
- 头部冗余与低效
- 每次请求需重复传输
User-Agent、Cookie等字段,浪费带宽(约500-800字节/请求)
- 每次请求需重复传输
- 连接数限制
- 浏览器对同一域名限制 6-8 个并发连接,资源加载需多次
TCP握手(3-RTT)
- 浏览器对同一域名限制 6-8 个并发连接,资源加载需多次
- 协议规范庞大
RFC2616长达176页,实现复杂且存在互操作性问题(如HTTP管道化未被广泛支持)
HTTP2的革新
- 核心目标
- 提升传输效率、降低延迟、支持现代
Web应用需求(如实时通信、高并发资源加载)
- 提升传输效率、降低延迟、支持现代
- 技术基础
- 基于
Google的SPDY协议演进,通过二进制分帧、多路复用等机制重构协议层
- 基于
协议内容
二进制分帧层
- 帧结构(9 字节头部 + 变长负载):
| 字段 | 长度 | 描述 |
| Length | 24 bits | 负载长度(不含帧头) |
| Type | 8 bits | 帧类型(如 DATA、HEADERS、PRIORITY) |
| Flags | 8 bits | 标志位(如 END_STREAM 表示流结束) |
| Stream ID | 31 bits | 流标识符(唯一标识逻辑通道) |
- 流(
Stream)- 逻辑双向通道,通过
Stream ID区分不同请求/响应,支持并发传输
- 逻辑双向通道,通过
- 消息(
Message):- 由多个帧组成的完整 HTTP 请求或响应(如
HEADERS+DATA)
- 由多个帧组成的完整 HTTP 请求或响应(如
多路复用
- 实现方式
- 单个
TCP连接上并发传输多个流的帧,消除队头阻塞
- 单个
|
1 2 |
Stream 1: HEADERS → DATA → END_STREAM Stream 3: HEADERS → DATA → END_STREAM |
- 优势
- 减少
TCP连接数,提升带宽利用率(对比HTTP/1.1提升40%+ 吞吐量)
- 减少
头部压缩(HPACK)
HPACK算法- 静态表:预定义
61个高频头部字段(如:method: GET、cookie) - 动态表:按需更新,存储新出现的头部键值对(
LRU淘汰策略) - 哈夫曼编码:对值进行压缩
- 静态表:预定义
- 压缩效果:
- 首次请求压缩率约
50%,后续请求可达90%
- 首次请求压缩率约
服务器推送
- 机制
- 服务端主动推送客户端可能需要的资源(如
CSS、JS),减少RTT
- 服务端主动推送客户端可能需要的资源(如
- 实现示例(
Nginx配置):
|
1 2 |
http2_push /style.css; # 推送 CSS 文件 http2_push_preload on; # 根据 Link 头部预加载资源 |
优先级与流量控制
- 优先级
- 通过
PRIORITY帧指定流的依赖关系和权重(如视频流优先于图片)
- 通过
- 流量控制
- 基于滑动窗口机制,防止接收端缓冲区溢出
支持的方法
概述
HTTP/2未引入新方法,完全兼容HTTP/1.1的语义,支持以下9种标准方法:GETPOSTHEADPUTDELETEOPTIONSTRACECONNECTPATCH
- 特性
- 所有方法通过二进制帧传输,支持多路复用和头部压缩
- 方法语义与
HTTP/1.1完全一致,开发者无需修改业务逻辑
CONNECT方法的扩展
HTTP/2对CONNECT方法进行了增强,支持Extended CONNECT Protocol- 用途
- 建立隧道以支持
WebSocket或其他应用层协议
- 建立隧道以支持
- 示例(
Node.js):- 服务端需启用
enableConnectProtocol设置 - 客户端通过
:protocol伪头部声明目标协议
- 服务端需启用
|
1 2 3 4 5 |
const req = client.request({ ':method': 'CONNECT', ':protocol': 'websocket', // 指定协议类型 ':authority': 'example.com:443' }); |
方法优化与性能影响
- 多路复用优势
- 所有方法均可通过单
TCP连接并发执行,消除HTTP/1.1的队头阻塞 - 示例:
GET请求加载页面时,同时发送POST提交数据,响应顺序可乱序返回
- 所有方法均可通过单
- 优先级控制
- 通过
PRIORITY帧设置流依赖关系(如视频流优先于图片加载) - 示例配置(
Nginx):
- 通过
|
1 |
http2_push_preload on; # 结合优先级推送关键资源 |
相关库
nghttp2
- 专用
HTTP/2实现,支持客户端/服务器/代理,提供底层API和工具链 - 客户端示例代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#include <nghttp2/nghttp2.h> #include <iostream> // 发送回调函数 static ssize_t send_callback(nghttp2_session *session, const uint8_t *data, size_t length, int flags, void *user_data) { int sockfd = *(int *)user_data; ssize_t sent = send(sockfd, data, length, 0); if (sent < 0) { perror("send failed"); return NGHTTP2_ERR_CALLBACK_FAILURE; } return sent; } int main() { nghttp2_session_callbacks *callbacks; nghttp2_session_callbacks_new(&callbacks); nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); nghttp2_session *session; nghttp2_session_client_new(&session, callbacks, nullptr); // 构造 HEADERS 帧请求 nghttp2_nv hdrs[] = { {":method", (uint8_t*)"GET", 3}, {":path", (uint8_t*)"/api/data", 9}, {":authority", (uint8_t*)"example.com", 11} }; nghttp2_data_provider data_prd = {nullptr, nullptr}; int stream_id = nghttp2_submit_request(session, nullptr, hdrs, 3, &data_prd, nullptr); // 发送帧 uint8_t buffer[4096]; ssize_t rv = nghttp2_session_send(session); if (rv != 0) { std::cerr << "Error sending frames" << std::endl; } nghttp2_session_del(session); nghttp2_session_callbacks_del(callbacks); return 0; } |
Boost.Beast
- 基于
Boost.Asio,支持HTTP/WebSocket,适合高性能服务端开发
libcurl
- 多协议支持(含
HTTP/2),异步请求接口成熟
HTTP2核心改进与实现
多路复用
- 原理
- 通过单个
TCP连接并行传输多个请求/响应,避免了HTTP/1.1的队头阻塞问题
- 通过单个
- 示例(基于
nghttp2库)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <nghttp2/asio_http2_server.h> using namespace nghttp2::asio_http2; using namespace nghttp2::asio_http2::server; int main() { boost::system::error_code ec; http2 server; server.handle("/api/data", [](const request &req, const response &res) { res.write_head(200, {{"content-type", {"application/json"}}}); res.end(R"({"message": "HTTP/2 多路复用示例"})"); }); if (server.listen_and_serve(ec, "0.0.0.0", "3000", true)) { std::cerr << "Error: " << ec.message() << std::endl; } } |
头部压缩
- 原理
- 通过静态表和动态表压缩重复的
HTTP头部字段,减少冗余数据传输
- 通过静态表和动态表压缩重复的
- 示例
HTTP请求头User-Agent和Cookie在多次请求中仅需传输索引值
服务器推送
- 原理
- 服务器主动推送资源(如
CSS、JS),减少客户端请求次数
- 服务器主动推送资源(如
- 示例代码
|
1 2 3 4 5 6 7 8 9 |
server.handle("/index.html", [&](const request &req, const response &res) { // 推送 CSS 资源 auto push = res.push("/style.css"); push->write_head(200, {{"content-type", {"text/css"}}}); push->end("body { color: red; }"); res.write_head(200, {{"content-type", {"text/html"}}}); res.end("<html><link rel=stylesheet href=/style.css></html>"); }); |
HTTP2的瓶颈与解决方案
TCP层队头阻塞
- 问题
TCP丢包会导致所有流阻塞(即使其他流的数据已到达)
- 解决方案
HTTP/3采用QUIC协议替代TCP,QUIC基于UDP实现多路复用与快速恢复
TLS握手延迟
- 问题
TLS 1.2需1-RTT握手,首次连接延迟较高
- 解决方案
TLS 1.3支持0-RTT,HTTP/3QUIC集成TLS 1.3减少握手开销
协议兼容性
- 挑战
- 旧设备/浏览器不支持
HTTP/2(如IE11)
- 旧设备/浏览器不支持
- 策略
- 服务端降级为
HTTP/1.1,CDN动态适配协议版本
- 服务端降级为
其他问题
TLS协议
- 概述
TLS(Transport Layer Security)是一种为网络通信提供 保密性、数据完整性 和 身份认证 的安全协议- 其前身为
SSL(Secure Sockets Layer),由网景公司于1994年首次提出,后由IETF标准化为TLS
- 功能
- 加密通信:通过对称加密算法(如
AES)保护数据传输隐私 - 身份验证:基于数字证书(
X.509)验证服务器或客户端身份 - 防篡改:利用哈希算法(如
SHA-256)生成消息认证码(MAC),确保数据未被篡改
- 加密通信:通过对称加密算法(如
- 发展历史
| 协议版本 | 发布时间 | 关键改进 |
SSL 1.0 |
未发布 | 存在严重安全漏洞,未公开使用 |
SSL 3.0 |
1996 年 |
引入对称加密和密钥交换机制,但因 POODLE 攻击等漏洞于 2014 年被弃用 |
TLS 1.0 |
1999 年 |
首个标准化版本,兼容 SSL 3.0,但存在降级攻击风险 |
TLS 1.2 |
2008 年 |
支持 SHA-256 等更强哈希算法,移除 MD5 和 SHA-1 依赖 |
TLS 1.3 |
2018 年 |
简化握手流程(1-RTT)、移除不安全算法(如 RSA 密钥交换)、支持前向安全性(Forward Secrecy) |
TLS协议核心机制
- 协议分层
TLS记录协议:负责数据分块、压缩、加密和传输,封装上层协议(如HTTP)的数据TLS握手协议:协商加密算法、交换密钥、验证身份,建立安全会话
- 握手流程(以
TLS 1.3为例)Client Hello:客户端发送支持的密码套件列表和随机数Server Hello:服务端选择密码套件并返回随机数及数字证书- 密钥交换:客户端验证证书后,使用服务端公钥加密预主密钥(
Pre-Master Secret) - 会话密钥生成:双方通过随机数和预主密钥生成对称加密密钥
- 密钥交换算法
RSA:传统非对称加密(TLS 1.3已弃用)Diffie-Hellman(DH):支持前向安全性,如ECDHE(基于椭圆曲线)
TLS关键特性与优势
- 前向安全性(
Forward Secrecy)- 会话密钥独立于长期私钥,即使私钥泄露,历史通信仍安全(通过
ECDHE实现)
- 会话密钥独立于长期私钥,即使私钥泄露,历史通信仍安全(通过
- 会话恢复
- 通过
Session ID或Session Ticket复用先前协商的密钥,减少握手延迟
- 通过
- 算法灵活性
- 支持多种密码套件(如
TLS_AES_128_GCM_SHA256),可动态适配安全需求
- 支持多种密码套件(如
TLS场景
HTTPS:保护网站数据传输(默认端口443)- 电子邮件:加密
SMTP、IMAP和POP3协议(如STARTTLS扩展) - 即时通信:保障聊天内容隐私(如
WhatsApp的端到端加密基于TLS) - 物联网(
IoT):设备与云端的安全通信
关于握手流程1-RTT
- 概述
1-RTT(1 Round Trip Time) 是指客户端与服务器在 仅一次网络往返 内完成TLS握手并建立加密通信的能力- 这一特性在
TLS 1.3中被正式引入,显著降低了握手延迟,提升了性能
- 对比
TLS 1.2TLS 1.2需要2-RTT完成完整握手
如Client Hello→Server Hello→Key Exchange→FinishedTLS 1.3通过合并消息和优化算法,将握手压缩至1-RTT,同时支持0-RTT(会话恢复场景)
TLS 1.3 的 1-RTT 握手流程如下:
Client Hello- 客户端发送以下关键信息:
- 支持的
TLS版本(如TLS 1.3) - 密码套件列表(优先选择前向安全的
ECDHE算法) Client Random(客户端随机数)Key Share(客户端的椭圆曲线公钥参数,如x25519)
|
1 2 3 4 |
ClientHello Cipher Suites: TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256 Key Share: x25519 public key Supported Groups: x25519, secp256r1 |
Server Hello- 服务器响应包含:
- 选定的
TLS版本和密码套件(如TLS_AES_128_GCM_SHA256) Server Random(服务端随机数)Key Share(服务端的椭圆曲线公钥参数)
- 服务端完成握手
- 服务器在发送
Server Hello后,直接附加以下消息: Encrypted Extensions(扩展参数)Certificate(服务器证书,可选)Certificate Verify(证书签名验证)Finished(加密的握手摘要,用于完整性校验)
- 服务器在发送
- 客户端完成握手
- 客户端验证证书和签名后,发送:
Finished(加密的握手摘要)
- 此时双方已具备加密能力,可立即开始应用数据传输
关于TLS密钥生成
- 客户端和服务端通过
ECDHE算法 交换公钥 - 结合
Client Random和Server Random,生成 预主密钥(Pre-Master Secret) - 最终导出 主密钥(
Master Secret) 用于对称加密通信
HTTP3
概述
HTTP2的局限性
TCP层队头阻塞- 即使
HTTP/2通过多路复用解决了应用层队头阻塞,但TCP的丢包重传机制会导致所有流阻塞(如单个丢包影响整个连接)
- 即使
- 连接迁移问题
TCP连接依赖四元组(源IP、端口,目标IP、端口),网络切换时需重建连接,导致高延迟(如移动网络切换)
TLS握手开销TCP + TLS 1.2需1-RTT握手,首次连接延迟较高
- 协议僵化
TCP实现位于操作系统内核,升级困难;QUIC基于用户态,便于快速迭代
HTTP3的革新
- 核心目标
- 基于
QUIC协议实现更低的延迟、更高的可靠性和安全性,适应现代网络环境(如移动网络、高丢包率场景)
- 基于
- 技术基础
QUIC(Quick UDP Internet Connections)基于UDP,集成TLS 1.3,提供0-RTT握手和独立流复用
协议内容
QUIC 协议核心机制
- 基于
UDP- 绕过
TCP限制,减少内核依赖,支持用户态实现
- 绕过
- 多路复用与独立流
- 每个流(
Stream)通过Stream ID唯一标识,丢包仅影响当前流
- 每个流(
|
1 2 |
Stream 1: HEADERS → DATA → END_STREAM Stream 3: HEADERS → DATA → END_STREAM |
0-RTT握手- 客户端缓存服务器配置(
Server Config),首次连接1-RTT,后续会话0-RTT
- 客户端缓存服务器配置(
- 连接迁移
- 通过
Connection ID标识连接,IP/端口变更时无需重建连接
- 通过
连接迁移
- 原理
- 通过连接
ID(而非IP+端口)标识连接,支持网络切换(如Wi-Fi→5G)不断线
- 通过连接
- 场景
- 移动设备切换网络时,视频流传输无需重新建立连接
HTTP/3帧结构
- 帧类型:包括
DATA、HEADERS、PRIORITY等,与HTTP/2类似但基于二进制格式 - 帧头字段(以
DATA帧为例):
| 字段 | 长度 | 描述 |
| Length | 24 bits | 负载长度(不含帧头) |
| Type | 8 bits | 帧类型(如 0x00 表示 DATA) |
| Stream ID | 62 bits | 流标识符(最高位保留) |
头部压缩(QPACK)
QPACK算法:基于HPACK改进,支持乱序传输和动态表更新,避免HTTP/2的头部阻塞- 编码示例:静态表预定义常用头部(如
:method: GET),动态表按需更新
优先级与流量控制
- 优先级帧(
PRIORITY):- 指定流的依赖关系和权重(如视频流优先)
- 流量控制
- 基于滑动窗口机制,防止接收端缓冲区溢出
支持的方法
概述
HTTP/2未引入新方法,完全兼容HTTP/1.1的语义,支持以下9种标准方法:GETPOSTHEADPUTDELETEOPTIONSTRACECONNECTPATCH
相关库
nghttp3
- 专用
HTTP/3实现,支持客户端/服务器,底层依赖QUIC协议栈 - 客户端示例:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#include <nghttp3/nghttp3.h> #include <iostream> // 初始化回调函数 static ssize_t send_callback(nghttp3_conn *conn, const uint8_t *data, size_t len, int flags, void *user_data) { int sockfd = *(int *)user_data; ssize_t sent = send(sockfd, data, len, 0); return (sent < 0) ? NGHTTP3_ERR_CALLBACK_FAILURE : sent; } int main() { nghttp3_conn *conn; nghttp3_callbacks callbacks = {.send_data = send_callback}; nghttp3_option *opt; // 初始化连接选项 nghttp3_option_new(&opt); nghttp3_conn_client_new(&conn, &callbacks, opt, nullptr); // 构造请求头 nghttp3_nv hdrs[] = { {":method", (uint8_t*)"GET", 3}, {":path", (uint8_t*)"/api/data", 9}, {":authority", (uint8_t*)"example.com", 11} }; // 提交请求 int stream_id = nghttp3_conn_submit_request(conn, nullptr, hdrs, 3, nullptr, nullptr); // 发送数据 uint8_t buffer[4096]; ssize_t rv = nghttp3_conn_send(conn, buffer, sizeof(buffer)); if (rv < 0) { std::cerr << "Send error: " << nghttp3_strerror(rv) << std::endl; } // 清理资源 nghttp3_conn_del(conn); nghttp3_option_del(opt); return 0; } |
quiche
Cloudflare开源QUIC实现(Rust编写,支持C++绑定)
Boost.Beast
- 基于
Boost.Asio,实验性支持HTTP/3
MsQuic
- 微软开源库,集成 Windows 网络栈,高性能
QUIC实现
基于 QUIC 协议
- 原理
- 使用
UDP替代TCP,解决TCP的队头阻塞问题,支持0-RTT快速握手
- 使用
- 示例代码(基于
quiche库):- 使用
quiche库(Cloudflare开源)实现QUIC连接
- 使用
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <quiche.h> #include <netinet/in.h> int main() { // 初始化 QUIC 连接 quiche_config *config = quiche_config_new(QUICHE_PROTOCOL_VERSION); quiche_config_set_application_protos(config, (uint8_t *)"\x05h3-29", 6); // 创建 QUIC 服务器 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(443)}; bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)); // 处理 QUIC 数据包 uint8_t buf[1200]; ssize_t len = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL); quiche_conn *conn = quiche_accept(buf, len, (struct sockaddr*)&addr, config); } |
HTTP3的瓶颈与解决方案
协议兼容性
- 问题
- 旧设备/中间件(防火墙、路由器)可能不支持
UDP/QUIC,导致连接失败
- 旧设备/中间件(防火墙、路由器)可能不支持
- 解决方案
- 通过
Alt-Svc头部协商协议(如Alt-Svc: h3=":443")
- 通过
0-RTT安全隐患
- 问题
0-RTT数据可能遭受重放攻击
- 解决方案
- 服务端限制
0-RTT数据为幂等操作,并采用TLS 1.3的防重放机制
- 服务端限制
UDP穿透能力
- 问题
NAT设备对UDP支持较差,导致丢包率上升
- 优化
- 使用前向纠错(
FEC)和冗余数据包减少重传
- 使用前向纠错(
性能调优
- 拥塞控制:
QUIC支持BBR或Cubic算法,需根据网络动态调整 Nginx配置示例:
|
1 2 3 4 5 6 |
http { listen 443 quic reuseport; # 启用 QUIC add_header Alt-Svc 'h3=":443"; ma=86400'; # 声明 HTTP/3 支持 ssl_protocols TLSv1.3; # 强制 TLS 1.3 quic_retry on; # 启用 QUIC 重试机制 } |
HTTP/2和HTTP/3对比
| 特性 | HTTP/2 | HTTP/3 |
| 传输层协议 | TCP(存在队头阻塞) | QUIC(基于 UDP,无队头阻塞) |
| 握手延迟 | 1-RTT(TCP + TLS) | 0-RTT(首次连接缓存密钥) |
| 头部压缩算法 | HPACK(依赖顺序传输) | QPACK(支持乱序更新) |
| 适用场景 | 稳定网络环境(如有线宽带) | 高丢包/移动网络(如 5G、IoT) |
记忆总结
HTTP1.1
核心特性
- 持久连接(
Keep-Alive)- 默认复用 TCP 连接,减少重复握手开销,但同一连接中的请求需按顺序处理,存在 队头阻塞(
Head-of-Line Blocking)
- 默认复用 TCP 连接,减少重复握手开销,但同一连接中的请求需按顺序处理,存在 队头阻塞(
- 管线化(
Pipelining)- 允许客户端发送多个请求,但服务端必须按顺序响应,实际应用受限(如非幂等请求可能导致问题)
- 分块传输(
Chunked Encoding)- 支持动态生成内容的分块传输,无需提前计算总大小
- 缓存优化
- 引入
Cache-Control、ETag等头部,支持更灵活的缓存策略
- 引入
Host头- 支持虚拟主机,允许同一
IP托管多个域名
- 支持虚拟主机,允许同一
局限
- 队头阻塞严重(同一连接请求需顺序处理)
- 明文传输,安全性差
- 头部冗余,无压缩机制
HTTP2
核心改进
- 二进制协议
- 替代文本格式,提升解析效率,减少错误
- 多路复用(
Multiplexing)- 单
TCP连接上并行处理多个请求/响应,解决应用层队头阻塞(但TCP层仍存在队头阻塞)
- 单
- 头部压缩(
HPACK)- 减少重复头部传输,节省带宽(压缩率高达
90%)
- 减少重复头部传输,节省带宽(压缩率高达
- 服务端推送(
Server Push)- 主动推送关联资源(如
CSS/JS),减少客户端请求延迟
- 主动推送关联资源(如
- 流优先级
- 按优先级传输资源(如优先加载
HTML骨架)
- 按优先级传输资源(如优先加载
局限
- 仍依赖
TCP,丢包时所有流被阻塞 - 需强制
TLS加密(主流浏览器要求HTTPS)
HTTP3
核心改革
- 基于
QUIC协议- 底层改用
UDP,彻底解决TCP队头阻塞,每个流独立传输
- 底层改用
0-RTT握手- 首次连接
1-RTT,后续会话0-RTT(需缓存服务器配置)
- 首次连接
QPACK头部压缩- 针对 QUIC 优化的压缩算法,支持乱序传输
- 强制加密
- 集成
TLS 1.3,所有通信默认加密
- 集成
- 连接迁移
- 网络切换(如
Wi-Fi → 5G)时保持连接,无需重建
- 网络切换(如
优势场景
- 高丢包网络(如移动环境)
- 高频短连接(如
API调用) - 实时通信(如视频流、在线游戏)
对比表
| 特性 | HTTP/1.1 | HTTP/2 | HTTP/3 |
| 底层协议 | TCP | TCP | UDP(QUIC) |
| 连接复用 | 持久连接(Keep-Alive) | 多路复用 | 独立流复用 |
| 队头阻塞 | 应用层 & TCP 层 | 仅 TCP 层 | 完全解决 |
| 头部压缩 | 无 | HPACK | QPACK |
| 加密强制 | 无(需手动 HTTPS) | 主流强制 | 协议内建 |
| 握手延迟 | 高(3-RTT) | 中(1-RTT) | 低(0-RTT 恢复) |
| 典型应用场景 | 传统 Web 页面 | 现代多资源网站 | 移动端、实时通信 |
声明:本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!