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
种标准方法:GET
POST
HEAD
PUT
DELETE
OPTIONS
TRACE
CONNECT
PATCH
- 特性
- 所有方法通过二进制帧传输,支持多路复用和头部压缩
- 方法语义与
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/3
QUIC
集成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.2
TLS 1.2
需要2-RTT
完成完整握手
如Client Hello
→Server Hello
→Key Exchange
→Finished
TLS 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
种标准方法:GET
POST
HEAD
PUT
DELETE
OPTIONS
TRACE
CONNECT
PATCH
相关库
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所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ CAN-BUS协议11/28
- ♥ 【Javascript】数字字符串07/01
- ♥ 网络相关11/21
- ♥ COM组件_403/07
- ♥ libcurl简述11/20
- ♥ KWP2000协议04/14