HTTP和TCP相关
开篇:HTTP 从 1.0 到 3.0 的进化
HTTP 是互联网上最重要的应用层协议,没有之一。从 1996 年的 HTTP/1.0 到 2022 年的 HTTP/3,每一次大版本升级都在解决一个核心问题:怎么让网页加载更快。
这篇文章我们来聊聊 HTTP 的核心知识:状态码与方法、缓存机制、HTTPS 的加密原理,以及 HTTP 协议的演进之路。
一、HTTP 状态码与方法
1.1 常见状态码
HTTP 状态码用 3 位数字表示服务器对请求的处理结果,分为 5 大类:
| 分类 | 含义 | 常见状态码 |
|---|---|---|
| 1xx | 信息提示,还在处理中 | 100 Continue |
| 2xx | 成功 | 200 OK, 204 No Content, 206 Partial Content |
| 3xx | 重定向 | 301 永久重定向, 302 临时重定向, 304 协商缓存命中 |
| 4xx | 客户端错误 | 400 Bad Request, 403 Forbidden, 404 Not Found |
| 5xx | 服务端错误 | 500 Internal Error, 501 Not Implemented, 503 Service Unavailable |
几个容易混淆的状态码:
- 301 vs 302:301 是永久搬家,浏览器和搜索引擎会缓存新地址,以后直接去新地址。302 是临时搬家,每次还是先去老地址再跳转。两者都通过响应头的
Location字段指定新 URL。 - 304:不是"重定向",而是告诉客户端"你本地的缓存还能用,直接拿缓存吧"。
- 403 vs 404:403 是"我知道你要什么,但你没权限"。404 是"你要的东西根本不存在"。
1.2 GET vs POST
这两个是最常用的 HTTP 方法。它们的核心区别在于语义:
| 对比项 | GET | POST |
|---|---|---|
| 语义 | 从服务器获取资源 | 向服务器提交数据 |
| 参数位置 | URL 中(查询字符串) | 请求体(Body)中 |
| 安全性 | 安全(只读操作) | 不安全(修改数据) |
| 幂等性 | 幂等(多次请求结果相同) | 不幂等(多次请求可能产生不同结果) |
| 缓存 | 可被浏览器缓存 | 默认不缓存 |
| 长度限制 | 受浏览器 URL 长度限制 | 理论上无限制 |
需要注意的是,GET 和 POST 的区别更多是语义上的约定而非技术上的硬性限制。从技术上讲,GET 也可以有 Body,POST 也可以把参数放在 URL 上。但遵循语义约定是良好的工程实践。
1.3 常见请求头字段
- Host:请求目标服务器的域名
- Content-Length:响应体的数据长度(也是解决 TCP 粘包的关键手段)
- Content-Type:数据类型(如
application/json、text/html) - Content-Encoding:数据压缩方式(如
gzip) - Connection:设为
Keep-Alive开启长连接(HTTP/1.1 默认开启)
二、HTTP 缓存机制
缓存是 Web 性能优化的第一利器。HTTP 缓存分为两种:强缓存和协商缓存。
2.1 强缓存:不问服务器,直接用
强缓存的核心思想是:浏览器自己判断缓存是否过期。如果没过期,直接从本地读取,连请求都不发。
控制强缓存的两个响应头:
- Expires(HTTP/1.0):绝对时间。
Expires: Thu, 01 Dec 2025 16:00:00 GMT,表示在这个时间点之前缓存有效。缺点是依赖客户端时钟,如果客户端时间不准就出问题。 - Cache-Control(HTTP/1.1,优先级更高):相对时间。
Cache-Control: max-age=3600,表示从响应生成开始 3600 秒内缓存有效。
强缓存命中时,浏览器直接从缓存读取,状态码显示 200 (from disk cache) 或 200 (from memory cache)。
优点:零网络请求,加载速度最快。
缺点:如果资源在服务器上更新了,客户端不知道,可能看到旧内容。
2.2 协商缓存:问一下服务器,还能用吗?
协商缓存的核心思想是:浏览器带着缓存标识问服务器"我的缓存还新鲜吗?"。如果服务器说"还新鲜",返回 304,浏览器用缓存。如果说"过期了",返回 200 和新内容。
有两套实现机制:
第一套:Last-Modified + If-Modified-Since
- 首次请求时,服务器在响应头带上
Last-Modified: Wed, 01 Jan 2025 00:00:00 GMT(资源最后修改时间) - 再次请求时,浏览器在请求头带上
If-Modified-Since: Wed, 01 Jan 2025 00:00:00 GMT - 服务器对比:如果资源在这个时间之后没修改过 → 返回 304;修改过 → 返回 200 + 新内容
缺点:精度只到秒级,如果 1 秒内修改了多次,检测不到。
第二套:ETag + If-None-Match(优先级更高)
- 首次请求时,服务器根据资源内容生成一个唯一标识 ETag(类似哈希值),放在响应头
- 再次请求时,浏览器在请求头带上
If-None-Match: "etag-value" - 服务器对比 ETag:没变 → 304;变了 → 200 + 新内容
ETag 基于内容生成,精度更高,但服务器需要额外计算,有性能开销。
2.3 缓存决策流程
三、HTTPS:给 HTTP 穿上盔甲
HTTP 是明文传输的,就像寄明信片——邮递员一路上都能看到你写了什么。HTTPS 就是在 HTTP 和 TCP 之间加了一层 SSL/TLS 加密协议,把明信片变成了密封信。
3.1 HTTP 和 HTTPS 的区别
| 对比项 | HTTP | HTTPS |
|---|---|---|
| 默认端口 | 80 | 443 |
| 安全性 | 明文传输,不安全 | 加密传输,安全 |
| 证书 | 不需要 | 需要 CA 数字证书 |
| 连接过程 | TCP 三次握手后直接传数据 | TCP 三次握手 + TLS 握手后传数据 |
| 性能 | 较快 | 稍慢(加解密有开销,但现代硬件影响极小) |
HTTPS 解决了 HTTP 的三大安全风险:
- 窃听:加密传输,中间人看不懂内容
- 篡改:数据完整性校验,篡改后会被检测到
- 冒充:数字证书验证服务器身份,防止钓鱼网站
3.2 TLS 握手过程
TLS 握手在 TCP 三次握手之后进行,目的是安全地协商出一个对称加密密钥。
以 TLS 1.2 为例(需要 2 个往返,共 4 步):
- ClientHello:客户端发送支持的 TLS 版本、加密算法列表、客户端随机数
- ServerHello:服务端选定 TLS 版本和加密算法,发送服务端随机数、数字证书、密钥交换参数
- 客户端验证证书:验证证书合法性,生成预主密钥,用服务端公钥加密后发送。双方各自用三个随机数计算出会话密钥
- Finished:双方发送加密的 Finished 消息验证握手完整性
TLS 1.3 做了优化,只需要 1 个往返(2 步):
- ClientHello:包含加密算法和密钥共享(Key Share),把密钥交换提前了
- ServerHello:选择参数、发送证书、直接生成会话密钥并响应
TLS 1.3 甚至支持 0-RTT 恢复——如果之前建立过连接,可以在第一个数据包中就携带加密数据,实现零延迟恢复。
3.3 对称加密 + 非对称加密的配合
HTTPS 的加密策略很巧妙:
- 非对称加密用来安全交换密钥(解决密钥分发问题)
- 对称加密用来加密后续的通信数据(保证传输速度)
单独用对称加密?密钥怎么安全传给对方是个问题。
单独用非对称加密?太慢了,性能扛不住。
两者结合,取长补短。
四、HTTP/1.1 → HTTP/2 → HTTP/3 演进
HTTP 协议的每一次升级都在追求更快的速度。来看看它们各自解决了什么问题。
4.1 HTTP/1.1:持久连接
HTTP/1.0 每次请求都要新建一个 TCP 连接。一个网页上有 100 个图片,就要建立 100 次 TCP 连接,每次都要三次握手,非常低效。
HTTP/1.1 引入了持久连接(Keep-Alive),一个 TCP 连接可以发送多个 HTTP 请求,大大减少了握手开销。
但 HTTP/1.1 还是有问题:HTTP 队头阻塞。虽然可以在一个连接上发送多个请求,但响应必须按顺序返回。如果第一个请求的响应很慢,后面的请求都得排队等着。就像单车道公路上前面的车开得慢,后面的车再快也超不过去。
4.2 HTTP/2:多路复用
HTTP/2 是一个里程碑式的升级,主要引入了四大特性:
二进制分帧:HTTP/1.x 使用文本格式传输,HTTP/2 改为二进制格式,解析效率更高。在应用层和传输层之间加了一个二进制分帧层。
多路复用:同一个 TCP 连接上可以同时发送多个请求和响应,它们被拆成一个个独立的帧(Frame),互不依赖,可以乱序发送,到达后再重新组装。这就彻底解决了 HTTP 队头阻塞的问题。
头部压缩(HPACK):HTTP/1.x 的请求头每次都要完整发送,很多内容是重复的。HTTP/2 使用 HPACK 算法对头部进行压缩,只发送变化的部分。
服务器推送:服务器可以主动把客户端还没请求的资源推送过来。比如客户端请求一个 HTML 页面,服务器预判到它接下来需要 CSS 和 JS 文件,主动推送过去并让客户端缓存。
HTTP/2 解决了 HTTP 层面的队头阻塞,但没有解决 TCP 层面的队头阻塞。TCP 要求数据包严格按顺序到达,如果中间有一个包丢了,后面所有的包都要等它重传。而且 HTTP/2 所有请求共用一个 TCP 连接,一旦丢包,所有请求都受影响。
4.3 HTTP/3:基于 QUIC(UDP)
为了彻底解决 TCP 的队头阻塞和握手延迟问题,HTTP/3 做了一个大胆的决定:放弃 TCP,改用基于 UDP 的 QUIC 协议。
为什么不直接升级 TCP?因为"协议僵化"——TCP 的实现在操作系统内核和无数中间设备(路由器、交换机、防火墙)中,全部更新的代价是不可接受的。QUIC 在应用层实现,绕开了这个问题。
QUIC 的核心特性:
- 基于 UDP:绕开了 TCP 的限制和"协议僵化"
- 内建可靠性:在 UDP 之上实现了类似 TCP 的确认、重传、拥塞控制
- 消除队头阻塞:多个数据流之间互相独立,一个流的丢包不影响其他流
- 0-RTT 建连:首次连接 1-RTT,恢复连接 0-RTT,速度极快
- 强制 TLS 1.3 加密:安全性内建,不可关闭
- 连接迁移:使用连接 ID 而非 IP+端口标识连接,WiFi 切移动网络时连接不断
4.4 各版本对比总结
| 特性 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 传输协议 | TCP | TCP | QUIC (UDP) |
| 多路复用 | 不支持 | 支持 | 支持 |
| 连接复用 | Keep-Alive | 单连接多路复用 | 单连接多路复用 |
| 头部压缩 | 不支持 | HPACK | QPACK |
| 队头阻塞 | HTTP + TCP 双重 | 仅 TCP 层 | 无 |
| 建连延迟 | 1.5 RTT (TCP) | 1.5 RTT (TCP) | 1 RTT (首次) / 0 RTT (恢复) |
| 加密 | 可选 | 常用 TLS | 强制 TLS 1.3 |
五、常见面试题精选
5.1 HTTPS 建立连接总共几次握手?
先进行 TCP 的 3 次握手建立可靠连接,然后进行 TLS 数据交换建立加密通道。
TLS 的交换次数取决于版本:TLS 1.2 需要 2 个往返(4 步),TLS 1.3 优化到 1 个往返(2 步)。
所以:TCP 3 次握手 + TLS 1.2 = 总共约 3.5 个 RTT 延迟;TCP 3 次握手 + TLS 1.3 = 总共约 2.5 个 RTT 延迟。
注意:TLS 的数据交换严格来说不叫"握手",它只是在已建立的 TCP 连接上进行的数据交换。
5.2 HTTP/2 解决了什么问题?还有什么没解决?
解决了:HTTP 队头阻塞(通过多路复用)、头部冗余(通过 HPACK 压缩)、服务器被动等待(通过服务器推送)。
没解决:TCP 队头阻塞。HTTP/2 的所有请求共用一个 TCP 连接,TCP 要求严格按序到达,一个包丢失会阻塞所有流。而且 HTTP/2 只允许一个域名一个 TCP 连接(HTTP/1.1 允许 6 个),所以 TCP 丢包时影响面更大。
这也是 HTTP/3 选择放弃 TCP 转投 QUIC(UDP)的根本原因。
5.3 HTTP 缓存中 ETag 和 Last-Modified 怎么选?
两者都是协商缓存的机制。ETag 优先级更高(如果同时存在,以 ETag 为准)。
选择建议:
- 对精度要求高的资源(频繁更新):用 ETag
- 对性能敏感的场景(减少服务端计算):用 Last-Modified
- 通常两者同时使用,互为补充
小结
HTTP 协议的演进史就是一部"追求更快"的历史。从 1.0 的一次一连接,到 1.1 的持久连接,到 2.0 的多路复用,再到 3.0 放弃 TCP 拥抱 QUIC,每一步都在解决上一代遗留的性能瓶颈。
理解 HTTP 状态码、缓存机制(强缓存 vs 协商缓存)、HTTPS 的加密原理、以及 HTTP 各版本的核心改进,这些知识无论在面试中还是日常开发中都会反复用到。
附录:TLS 和 SSL 的关系
很多人分不清 TLS 和 SSL。简单来说:SSL 是前辈,TLS 是继任者。
SSL(Secure Sockets Layer)由 Netscape 在 1990 年代开发,经历了 1.0、2.0、3.0 三个版本。但 SSL 各版本都存在安全漏洞,现在已经全部废弃。
TLS(Transport Layer Security)是 SSL 的标准化继任者。目前广泛使用的是 TLS 1.2 和 TLS 1.3。
| 版本 | 状态 | 说明 |
|---|---|---|
| SSL 1.0 / 2.0 / 3.0 | 已废弃 | 存在已知安全漏洞 |
| TLS 1.0 / 1.1 | 逐步淘汰 | 安全性不足,主流浏览器已停止支持 |
| TLS 1.2 | 广泛使用 | 当前主流 |
| TLS 1.3 | 推荐使用 | 更快(1-RTT 握手)、更安全 |
我们平时说的"HTTPS"、"SSL 证书"、"TLS 加密",本质上都是同一件事:在 HTTP 和 TCP 之间加一层加密协议。只是名字上的历史遗留问题,"SSL 证书"其实早就是 TLS 证书了。
TLS 1.3 相比 1.2 的主要改进:
- 握手从 2-RTT 缩短到 1-RTT,支持 0-RTT 恢复
- 移除了不安全的加密算法(如 RC4、DES、SHA-1)
- 简化了密钥交换流程,只支持前向安全的算法(如 ECDHE)
- 加密了更多的握手信息,减少了元数据泄露
选择建议:新项目优先配置 TLS 1.3,同时兼容 TLS 1.2。TLS 1.1 及以下版本应尽快淘汰。