计算机网络之五 - HTTP 与 HTTPS
本系列的前几篇文章中,我们已经探讨了设备如何通过 IP 地址获得身份、如何通过 DNS 将域名解析为地址,以及如何通过 DHCP、NAT 和 VPN 等技术接入并穿梭于复杂的网络环境。至此,我们的设备已经具备了“定位”并“连接”到目标服务器的能力。
本文将深入探讨这个连接建立之后,应用程序之间进行通信所使用的“语言”——HTTP 协议,以及其安全版本 HTTPS。这两种协议构成了现代万维网的基石。
本系列其余几篇的目录:
- 计算机网络之一 - IP 与端口
- 计算机网络之二 - URL 与 DNS
- 计算机网络之三 - DHCP 与内网穿透
- 计算机网络之四 - 虚拟网卡与 WireGuard
- 计算机网络之六 - 可靠的 TCP 与高效的 UDP
前置知识说明:在阅读本文时,您会遇到 TCP 和 UDP 这两个概念。它们是网络通信的两种基础“运输方式”,我们将在本系列的下一篇文章中深入探讨。为方便您理解本文,您可以暂时将它们想象为:
- TCP:一种可靠的“电话通话”。在通话前,双方必须先建立连接,确保线路通畅,通话过程中能保证数据按顺序、不丢不漏地送达。
- UDP:一种简单的“明信片”。它直接将数据包发出,不保证一定或按序到达,但胜在快捷高效。
本文中提到的 HTTP/1.1 和 HTTP/2 都构建在可靠的 TCP 之上,而最新的 HTTP/3 则创造性地选择了 UDP 作为基础。带着这个初步印象,您就可以顺利地理解下文内容了。
HTTP:构建 Web 的无状态协议
HTTP (HyperText Transfer Protocol,超文本传输协议) 是一种用于分布式、协作式和超媒体信息系统的应用层协议。它是万维网数据通信的基础。
核心特性
- 基于“请求-响应”模式:通信由客户端发起。客户端向服务器发送一个 HTTP 请求,服务器在处理后返回一个 HTTP 响应。
- 无状态 (Stateless):协议本身不保存任何关于过去请求的信息。服务器处理每个请求时,都认为它是一个全新的、独立的事务,不依赖于之前的请求。您可以将它想象成一个记忆力很短的接待员,处理完你的当前请求后,立刻就会忘记你是谁。为了让它记住你,就需要 Cookies 这样的“身份牌”来帮忙。
- 灵活可扩展:通过请求头和响应头,HTTP 允许传输任意类型的数据,不仅仅是 HTML,还包括图片、视频、JSON 等。其基础交互模型如下所示:
HTTP 报文结构
HTTP 通信由纯文本的报文(Message)组成,分为请求报文和响应报文。
不知道你有没有想过为什么“message”被翻译成了“报文”?其实是因为前辈们沿用了“电报”时代的相关概念,那时“报文”一词就已经蕴含了“通过电子信号传递的、有特定格式的文书”的意义。另外,“报”字蕴含了遵循协议的规范性,而“文”字则强调了其内容与格式的结构化,如同一份严谨的文书。所以最终这个概念的中文被译为了“报文”。
至于为何英语沿用通用的“message”而非更专业的词,是因为“message”本就是指代通信内容的基础词,而“telegraph”(电报)则指通信系统本身,而非内容单元。英语习惯用限定词(如 HTTP message)来明确上下文,无需替换基础词。这是两种语言在技术术语演变上的路径差异。
请求报文 (Request Message)
一个典型的 HTTP GET 请求报文结构如下:
GET /path/to/resource/index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...
Accept: text/html,*/*
Accept-Language: en-US,en;q=0.5
它由三部分构成:
- 请求行 (Request Line):包含请求方法(
GET
)、请求资源的路径(/path/...
)和 HTTP 协议版本(HTTP/1.1
)。 - 请求头 (Headers):以键值对形式提供关于请求的元数据,或客户端自身的信息。例如
Host
指定了目标服务器的域名,User-Agent
描述了客户端的类型。 - 请求体 (Body):对于
GET
请求,请求体为空。对于POST
或PUT
请求,这里会包含需要提交给服务器的数据,例如表单信息或 JSON 数据。
常见的请求方法(Method)有:
方法 | 描述 |
---|---|
GET |
请求获取指定资源。 |
POST |
向指定资源提交数据,请求服务器进行处理(例如提交表单或上传文件)。 |
PUT |
用请求中的数据体替换目标资源的全部当前内容。 |
DELETE |
请求服务器删除指定的资源。 |
HEAD |
与 GET 类似,但服务器在响应中只返回头部,不返回实体主体内容。 |
响应报文 (Response Message)
服务器在收到并处理请求后,会返回一个响应报文:
HTTP/1.1 200 OK
Date: Mon, 18 Aug 2025 10:00:00 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 1270
<!DOCTYPE html>
<html>
...
</html>
它同样由三部分构成:
- 状态行 (Status Line):包含 HTTP 协议版本、状态码(
200
)和状态描述(OK
)。 - 响应头 (Headers):提供关于响应的元数据,如
Content-Type
指明了响应体的媒体类型。 - 响应体 (Body):实际返回的资源内容,例如 HTML 文档。
状态码是服务器对请求处理结果的标准化表示,常见的有:
有一个很好玩的小网站分享给大家:https://http.cat/ ,用可爱的猫猫表示 HTTP 状态码。
状态码 | 名称 | 类别 | 描述 |
---|---|---|---|
200 |
OK | 成功 | 请求已成功。 |
201 |
Created | 成功 | 请求成功,并因此创建了一个新的资源。 |
204 |
No Content | 成功 | 服务器成功处理了请求,但没有返回任何内容。 |
301 |
Moved Permanently | 重定向 | 请求的资源已被永久移动到新位置。 |
302 |
Found | 重定向 | 请求的资源被临时重定向到另一个 URI。 |
304 |
Not Modified | 重定向 | 用于缓存。表示资源未被修改,客户端可以继续使用已缓存的版本。 |
400 |
Bad Request | 客户端错误 | 由于语法无效,服务器无法理解该请求。 |
401 |
Unauthorized | 客户端错误 | 请求要求身份验证。客户端需要提供凭据。 |
403 |
Forbidden | 客户端错误 | 服务器理解请求,但拒绝执行。与 401 不同,身份验证无法改变结果。 |
404 |
Not Found | 客户端错误 | 服务器找不到请求的资源。 |
405 |
Method Not Allowed | 客户端错误 | 服务器知道请求的方法,但目标资源不支持该方法。 |
429 |
Too Many Requests | 客户端错误 | 用户在给定的时间内发送了太多的请求(速率限制)。 |
500 |
Internal Server Error | 服务器错误 | 服务器遇到了一个未曾预料的状况,导致其无法完成对请求的处理。 |
502 |
Bad Gateway | 服务器错误 | 作为网关或代理的服务器,从上游服务器收到了无效的响应。 |
503 |
Service Unavailable | 服务器错误 | 服务器当前无法处理请求(由于超载或停机维护)。 |
为了更直观地对比,下表总结了请求报文与响应报文的核心区别:
构成部分 | 请求报文 (Request) | 响应报文 (Response) |
---|---|---|
起始 (行) |
格式:方法 URI HTTP版本 示例: GET /index.html HTTP/1.1 |
格式:HTTP版本 状态码 描述 示例: HTTP/1.1 200 OK |
首部 (头) |
描述客户端信息、请求的资源等。 示例: Host , User-Agent |
描述服务器信息、返回内容的类型等。 示例: Content-Type , Server |
正文 (体) |
通常用于 POST 等方法,携带提交给服务器的数据。GET 请求通常为空。 |
包含返回给客户端的实际资源内容,如 HTML 文档、JSON 数据等。 |
HTTP 的版本演进与协商机制
HTTP 协议并非一成不变,它在过去几十年中经历了数次重要迭代,以适应日益复杂的 Web 应用和用户对性能的更高要求。
HTTP/1.0 与 HTTP/1.1
- HTTP/1.0 (1996):作为早期版本,其主要特点是短连接。每次请求都需要建立一个新的 TCP 连接,请求完成后立即断开,效率低下。
- HTTP/1.1 (1999):这是统治了互联网近 20 年的经典版本。它最重要的改进是引入了持久连接(Keep-Alive),允许在同一个 TCP 连接上发送多个请求,极大地减少了连接建立的开销。但它也存在一个著名的问题——队头阻塞(Head-of-Line Blocking),即在一个连接上,前一个请求的响应必须完全接收后,后续的请求才能被处理,导致效率瓶颈。
HTTP/2 (2015)
HTTP/2 的目标是彻底解决 HTTP/1.1 的性能问题,其核心改进包括:
- 二进制分帧:将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式编码,解析效率更高。
- 多路复用 (Multiplexing):这是 HTTP/2 最具革命性的特性。它允许在单个 TCP 连接上同时、并行地发送和接收多个请求和响应,彻底解决了队头阻塞问题。
- 头部压缩 (HPACK):使用特定算法压缩冗余的请求头和响应头,减少了传输的数据量。
HTTP/3 (2022)
HTTP/3 的演进更进一步,它将底层的传输协议从 TCP 换成了 QUIC。
- 基于 QUIC:QUIC 是一个基于 UDP 的新传输协议,它整合了 TCP 的可靠性、TLS 的安全性以及更多新特性。
- 解决 TCP 队头阻塞:HTTP/2 虽然解决了应用层的队头阻塞,但无法解决 TCP 协议本身的队头阻塞(一个数据包丢失,整个连接都要等待重传)。QUIC 基于 UDP,一个流的丢包不会影响其他流,从根本上解决了这个问题。
- 更快的连接建立:QUIC 将 TCP 和 TLS 的握手过程合并,减少了建立连接所需的往返时间(RTT),让连接更快。
版本协商:客户端与服务器如何“对暗号”?
既然有这么多版本,客户端和服务器是如何确定使用哪个版本的呢?这个过程被称为协议协商。
- HTTP/2 的协商:这是一个有趣的地方。虽然 HTTP/2 的协议规范本身并不强制加密(存在明文的
h2c
模式),但所有主流浏览器都达成了一个共识:只支持通过 HTTPS 运行的 HTTP/2。这既是为了推动全网加密,也是为了绕过可能不支持新协议的旧网络设备。因此,在浏览器实践中,HTTP/2 的协商几乎总是通过 TLS 的一个扩展 ALPN (Application-Layer Protocol Negotiation) 来实现。在 TLS 握手时,客户端会告诉服务器它支持的协议列表(如["h2", "http/1.1"]
),服务器则从中选择一个它也支持的最高版本,并在 TLS 握手完成时通知客户端。 - HTTP/3 的协商:由于 HTTP/3 运行在不同的协议(UDP)上,它的发现机制有所不同。通常,服务器会通过 HTTP/1.1 或 HTTP/2 的响应头
Alt-Svc
(Alternative Service) 来“广播”自己的 HTTP/3 服务地址。例如,Alt-Svc: h3=":443"
。浏览器收到后,就会尝试在后台建立一个到该地址的 QUIC 连接,并在后续请求中升级到 HTTP/3。
HTTPS:为对话加上安全封印
HTTP 协议本身是明文传输的,这意味着任何在传输路径上的中间节点(如路由器、ISP)都能轻易地读取、甚至篡改通信内容。这带来了三大安全风险:
- 窃听风险 (Eavesdropping):通信内容可能被第三方窃听。
- 篡改风险 (Tampering):通信内容在传输过程中可能被修改。
- 冒充风险 (Impersonation):无法验证通信对方的真实身份,可能连接到伪造的服务器。
为了解决这些问题,HTTPS (HTTP Secure) 应运而生。
HTTPS 的核心
HTTPS 并非一个全新的协议,它的结构是 HTTPS = HTTP + TLS/SSL。它在标准的 HTTP 应用层和 TCP 传输层之间,增加了一个加密、认证和完整性保护的 TLS/SSL 安全层。
SSL (Secure Sockets Layer) 是 TLS (Transport Layer Security) 的前身,由于存在安全漏洞现已弃用。
我们目前实际使用的都是 TLS 协议,但出于历史习惯,人们常将二者并称为 TLS/SSL。
这个安全层主要提供三大核心安全保障:
- 加密 (Encryption):确保通信内容无法被窃听。有趣的是,这里使用的是对称加密。因为非对称加密虽然更灵活,但计算开销巨大,速度过慢,不适合加密海量的应用数据。而对称加密速度极快,正适合此场景。
- 身份验证 (Authentication):通过数字证书,客户端可以验证服务器的身份,确保连接到的是预期的、真实的服务器,防止冒充。
- 数据完整性 (Integrity):通过消息认证码(MAC),确保数据在传输过程中没有被篡改。
TLS 握手机制
当浏览器访问一个 HTTPS 网站时,在真正发送 HTTP 请求之前,它必须先与服务器完成一次 TLS 握手,以建立一个安全的信道。这个过程在概念上可以分为几个步骤,其交互流程可通过以下序列图来描述:
- 客户端问候 (Client Hello):客户端向服务器发起连接,并发送它支持的加密算法列表、TLS 版本等信息。
- 服务器响应与身份证明 (Server Hello & Certificate):服务器从中选择一套双方都支持的加密算法,然后将其数字证书(包含了服务器的公钥和由权威证书颁发机构 CA 的签名)发送给客户端。
- 客户端验证与密钥交换(非对称加密的应用):
- 客户端验证服务器证书的有效性(是否由受信任的 CA 签发、是否过期、域名是否匹配等)。
- 验证通过后,客户端生成一个用于本次会话的“暗号”(pre-master secret),然后使用从证书中获取的服务器公钥对其进行加密(非对称加密),并发送给服务器。
- 生成会话密钥与建立安全信道:服务器使用自己的私钥解密,是全网唯一能获取该“暗号”的实体。随后,客户端和服务器使用这个共享的“暗号”,通过相同的算法,各自生成出完全一样的对称会话密钥。握手完成。
- 安全通信:后续所有的 HTTP 数据都将使用这个对称密钥进行加密和解密,实现安全的通信。
在这个流程中,非对称加密(公钥/私钥)被巧妙地用于安全地协商和交换对称加密所使用的密钥,兼顾了安全性和性能。这就像用一把非常复杂、开锁很慢但无法被复制的钥匙(非对称加密),去打开一个保险箱,从里面取出一把开门又快又方便的普通钥匙(对称加密),然后锁上保险箱,以后进出都用这把普通钥匙。
TLS 握手与“三次握手”的区别
需要明确的是,TLS 握手不是我们常说的 TCP“三次握手”。这是一个非常常见但重要的混淆点,它们是两个发生在不同阶段、目的也完全不同的过程:
- 三次握手 (TCP Handshake):发生在传输层,目的是建立一个可靠的通信连接,确保双方都准备好了收发数据。它不关心内容是否加密。
- TLS 握手 (TLS Handshake):发生在 TCP 连接建立之后,目的是在已有的可靠连接上,再建立一个安全的加密信道,协商后续通信要使用的加密密钥。
简单来说,先有 TCP 三次握手建立起“物理通话线路”,再有 TLS 握手在这条线路上约定“加密暗号”。
融会贯通:连接系列知识
HTTP/HTTPS 作为应用层协议,其运行离不开底层网络设施的支持。
-
协议、端口与 DNS 的协同工作:在第二篇文章中我们了解到,URL
https://www.example.com
中的https
部分,正是告诉浏览器需要通过 443 端口(回顾第一篇)连接到由 DNS 解析出的 IP 地址,并启动上文所述的 TLS 握手流程。 -
应用层加密与网络层加密:HTTPS vs. WireGuard:在第四篇文章中,我们深入了 WireGuard。现在可以清晰地对比二者的区别:
- HTTPS 在应用层工作,它保护的是单个应用程序(如浏览器)与单个目标服务器之间的通信内容。它不关心数据包如何路由,只关心应用数据的安全。
- WireGuard 在网络层工作,它保护的是设备与VPN 服务器之间的所有 IP 流量。一旦连接,无论是 HTTP 请求、DNS 查询还是其他任何网络活动,都会被封装在加密隧道中。它提供的是全面的网络链路级安全。
总结
HTTP 定义了 Web 内容交换的基本规则,而 HTTPS 则为其增加了至关重要的安全保障。理解这两种协议的原理、结构以及它们在整个网络协议栈中的位置,是理解现代互联网运作方式的关键。它们与底层的 IP、DNS、TCP/UDP 等协议协同工作,共同构成了我们每天都在使用的、复杂而又高效的全球信息网络。