Skip to content

HTTP 协议

2026 大纲 六(五)2 HTTP 协议。万维网的整体结构与 URL 在 WWW 万维网,三报文握手本身的机制在 TCP 连接管理

速查

定位面向事务(一系列信息交换是不可分割的整体,要么全完成、要么一次都不进行)、面向文本的应用层协议,用 TCP 端口 80(HTTPS 443)
🔴 三句话各说一件事① HTTP 使用面向连接的 TCP;② 协议 HTTP 本身是无连接的(交换报文前不需要先建立 HTTP 连接);③ 协议 HTTP 是无状态的。"HTTP/1.1 有持久连接所以不是无连接协议"是错的——持久说的是底下那条 TCP 连接不立即关闭
为什么故意设计成无状态简化服务器设计,使服务器更容易支持大量并发请求。每个请求都能被独立处理,任何一台服务器都能接手任何一个请求——这是负载均衡与水平扩容的前提
🔴 取一个文档是 2 个 RTT 不是 3 个三报文握手的前两个报文完成后(即经过一个 RTT),客户就把 HTTP 请求报文作为握手第三个报文的数据发出去,所以第三个握手报文不额外占 RTT
四个 RTT 计数公式(1 个 HTML + N 个对象)非持久串行 2(1+N);非持久 M 并行 2+2N/M;持久非流水线 2+N;持久流水线 2+1=3
🔴 恒定的那个 2 躲不掉是取 HTML 本身的开销(建连 1 + 请求响应 1)——不拿到 HTML 就不知道页面引用了哪些对象
🔴 持久不一定比非持久快持久省的是建连 RTT,并行省的是排队轮数,优化维度不同。非持久 + 多条并行完全可能快过持久非流水线。代价是并行要在服务器上分配多份连接缓存与变量
🔴 持久连接不限于同一个页面只要这些文档都在同一个服务器上就能复用这条连接
🔴 流水线解决"请求要等",队头阻塞剩下"响应要排队"HTTP/1.1 流水线允许客户连发请求,但服务器必须按先后顺序排队逐个发回响应;真正把响应并行化的是 HTTP/2
幂等性看服务器最终状态执行 n 次与 1 次的服务器最终状态相同即幂等,与返回码无关——DELETE 重复执行会返回 404,但状态没变,仍幂等
🔴 "POST 比 GET 安全"要限定POST 只是参数不进 URL(不进历史、日志、Referer);报文体在 HTTP 下同样明文,抓包一样能看到。传输安全靠 HTTPS
🔴 304 不是错误属 3xx,表示资源未修改、可用本地缓存,不带实体主体;但它省不掉那一个 RTT,仍是一次完整往返
🔴 401 与 403401 = 你还没证明你是谁(缺鉴权);403 = 知道你是谁但不给(授权不足)
🔴 Cookie 没有让 HTTP 变成有状态协议状态是客户端每次重新携带的,服务器仍不主动保存客户身份。有状态的是建在 HTTP 之上的应用
Host 首部在 1.1 里是必须的一个 IP 上可放多个虚拟主机,服务器要靠它才知道客户要哪个站点——这也是 1.0 不支持虚拟主机的原因

一、请求方法

方法作用请求体幂等安全(不改服务器状态)
GET获取资源
POST提交数据(如表单)
PUT上传/替换资源
DELETE删除资源
HEAD同 GET,但只返回首部、不返回实体

PUT /user/3 做 5 次和做 1 次、用户 3 的最终内容一样;POST /user 每次都新建一条记录,做 5 次就多 5 条——这就是幂等与不幂等的分界。GET 与 POST 的其余差别:参数在 URL 查询字符串还是请求体里,前者受 URL 长度限制(协议本身没规定上限,是实现的限制)且可以被缓存,后者一般不缓存。

二、报文结构

两类报文都由开始行 + 首部行 + 空行 + 实体主体四部分组成,区别只在开始行:请求报文是请求行方法 URL 版本),响应报文是状态行版本 状态码 短语)。请求报文一般没有实体主体(GET 就没有),响应报文也可能没有(如 304)。

由于 HTTP 面向文本,报文中每个字段都是 ASCII 码串、长度都不确定,靠每行末尾的 CR+LF 划界——这与 TCP/IP 首部那种定长二进制字段是完全不同的设计。

两个报文样例:四个部分实际长什么样(想看清那个空行卡在哪一行时展开)

请求报文GET 没有实体主体,所以空行之后就没有内容了):

GET /index.html HTTP/1.1
Host: www.example.com
Connection: keep-alive
User-Agent: Mozilla/5.0
Accept: text/html

第 1 行是请求行方法 URL 版本),第 2~5 行是首部行,最后那个空行是首部与实体主体的分界——它必须存在,哪怕后面什么都没有。

响应报文

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234

<html>...</html>

第 1 行是状态行版本 状态码 短语),随后是首部行,空行之后才是实体主体Host 首部在请求里是 HTTP/1.1 强制要求的,Content-Length 则告诉对方实体主体有多长——面向文本的报文没有定长字段,实体的边界只能靠它(或分块编码)来定。

三、状态码

首位数字表示类别:1xx 信息性(收到了,继续)/2xx 成功(收到、理解、接受)/3xx 重定向(东西不在这,或你手上那份还能用)/4xx 客户端错误(你的请求有问题)/5xx 服务器错误(请求没问题,是我这边坏了)。

状态码含义要点
100 Continue收到请求的初始部分,可继续发送大请求体先探路
200 OK / 201 Created成功/资源已创建201 通常是 POST、PUT 的结果
301 Moved Permanently永久重定向搜索引擎更新索引,客户端可缓存这次跳转
302 Found临时重定向下次仍访问原地址
304 Not Modified资源未修改,可用缓存不带实体主体,是优化不是错误
400 Bad Request请求语法错误
403 Forbidden服务器拒绝请求服务器你的请求,但不给
404 Not Found资源不存在
500 Internal Server Error服务器内部错误
502 / 503网关收到无效响应/服务暂时不可用502 出问题的是上游;503 强调"暂时"

四、非持久连接与持久连接

T取一个文档=2×RTT+T传输

HTTP/1.0 非持久:每请求一个对象就建一条 TCP 连接、收到响应立刻关闭;代价除了每对象 2×RTT,还有每次新建连接都要分配缓存和变量——补救靠浏览器同时打开 5~10 条并行连接,这是用服务器资源换时间。HTTP/1.1 持久:服务器发送响应后仍在一段时间内保持这条连接。非流水线方式客户收到前一个响应后才能发下一个请求(每对象 1 个 RTT,省掉了建连那个);流水线方式客户在收到响应之前就能接着发新请求,服务器连续发回响应,因此客户访问所有对象只需花费一个 RTT

方式TCP 连接数RTT 个数
非持久 · 串行1+N2(1+N)
非持久 · M 条并行1+N2+2N/M
持久 · 非流水线12+N
持久 · 流水线13
四种方案的总时间逐步算(想确认自己能把每个 RTT 的来历说清时展开)

某网页含 1 个 HTML 文件和 8 个引用对象。RTT = 100 ms,链路速率 10 Mb/s,HTML 10 kb,每个对象 100 kb,忽略 DNS 解析与服务器处理时间。

第 1 步:先把传输时间单独算出来,它对四种方案都一样。RTT 数与文件大小无关、传输时间与 RTT 无关,两者可以分开算再相加;先把不变量提出来,后面只比 RTT 个数(注意 10 Mb/s = 10 000 kb/s):

T传输=1010000+8×10010000=1+80=81 ms

第 2 步:非持久串行。 9 个对象(含 HTML)每个都要"建连 1 + 请求响应 1",一个不落:2(1+8)=18 个 RTT =1800 ms,T=1881 ms。

第 3 步:非持久 + 5 条并行。 HTML 必须先单独取(不知道有哪些对象就没法并行),花 2 个 RTT;剩下 8 个对象分成 8/5=2 批——向上取整是因为第二批只有 3 个对象,但仍要占满一整轮。并行只压缩轮数,不改变每轮的 2 个 RTT:2+2×2=6 个 RTT =600 ms,T=681 ms。

第 4 步:持久非流水线。 连接只建一次,那 8 个建连 RTT 全省了;但请求必须串行,8 个来回一个不能少:2+8=10 个 RTT =1000 ms,T=1081 ms。

第 5 步:持久流水线。 8 个请求连着发出去、服务器连着回,全部压进一个来回:2+1=3 个 RTT =300 ms,T=381 ms。

方案TCP 连接数RTT 个数RTT 时间总时间
非持久 · 串行9181800 ms1881 ms
非持久 · 5 并行96600 ms681 ms
持久 · 非流水线1101000 ms1081 ms
持久 · 流水线13300 ms381 ms

最值得注意的是第 2 行:非持久 + 5 条并行(681 ms)竟然快过持久非流水线(1081 ms)——持久省的是建连 RTT,并行省的是排队轮数,两者优化的维度不同,所以"持久一定比非持久快"是错的。真正的组合拳是持久 + 流水线(381 ms),或 HTTP/2 的单连接多路复用。代价也要一并记住:并行方案的 9 条 TCP 连接要在服务器上分配 9 份缓存与变量,而持久流水线只占 1 条。

五、版本演进:一条追问链

特性HTTP/1.0HTTP/1.1HTTP/2HTTP/3
连接非持久(默认)持久(默认)持久 + 多路复用基于 QUIC
传输层TCPTCPTCPUDP
请求方式串行流水线(响应仍须排队)多路复用(响应可并行发回)多路复用
首部面向文本,不压缩面向文本,不压缩二进制分帧 + HPACK 压缩QPACK 压缩
服务器推送支持支持

非持久 → 每对象 2 RTT(持久解决)→ 请求要串行等待(流水线解决)→ 响应要排队(HTTP/2 多路复用解决)→ TCP 按序交付导致跨流阻塞(HTTP/3 换 UDP 解决)。每一步只解决上一步剩下的那个阻塞,顺着这条链走就不必单独记每个版本的特性表。

HTTP/2 的三点改进逐条对应 1.1 的一个缺陷:响应可并行发回、复用 TCP 连接、二进制分帧 + 首部压缩(连续请求时首部里大量字段是重复的)。它向后兼容:HTTP/2 的客户向仍跑 1.1 的服务器发请求时服务器照样收得到,发回响应后客户改用 1.1 交互。HTTP/3 换 UDP 的理由是 HTTP/2 只消除了应用层的队头阻塞,底下仍是单条 TCP——TCP 要求按序交付,一个报文段丢了,后面所有已到达的数据都得在内核里等它重传;QUIC 自己实现流的独立可靠传输,一条流丢包不阻塞其他流。

六、代理服务器与条件 GET

代理服务器又称万维网高速缓存:把最近的一些请求和响应暂存在本地磁盘中,新请求若与暂存的相同就直接返回,不必再按 URL 去互联网访问。

代理服务器有时是服务器(接受浏览器请求时),有时是客户(向源点服务器发请求时)——角色由通信关系决定,与 网络应用模型 说的是同一件事。它的三项收益受益方不同:减少响应时间(用户)、减少机构出口链路流量(机构)、热门资源被缓存后源点请求量大幅下降(内容提供方)。规模化形态就是内容分发网络 CDN

条件 GET 省掉的是实体主体的传输,省不掉那一个 RTT。 所以缓存验证只在"对象大、变化少"时划算——这也是静态资源要配长 TTL 而不是每次都验证的原因。

七、Cookie 与 Session

服务器在响应中用 Set-Cookie 首部设置 Cookie,客户端保存后在后续每个请求Cookie 首部里自动带上,服务器据此识别客户端。Session 则是服务器端保存的会话信息:服务器为每个会话分配一个 Session ID,通过 Cookie 发给客户端,客户端后续请求携带这个 ID,服务器据此找到对应的会话状态。

CookieSession
存在哪客户端服务器端
随请求传输的内容全部内容只有 Session ID
安全性内容在客户端,可被查看/篡改客户端只拿到一个 ID
服务器开销要为每个会话保存状态

本节小结

  1. 三句独立的话:HTTP 使用 TCP 连接 / 协议本身无连接 / 协议无状态;无状态是为了简化服务器、支撑高并发。请求与响应报文只在开始行不同,面向文本导致字段长度不定、靠 CRLF 划界。
  2. RTT 计数是本节的计算核心,地基是"请求捎带在握手第三个报文里,所以取一个文档 2 RTT"。四个公式为 2(1+N)2+2N/M2+N3,恒定的那个 2 是取 HTML 的开销。持久省建连、并行省轮数、流水线省排队,三者优化维度不同,不能简单说谁快。
  3. 版本演进是一条追问链:非持久 → 持久 → 流水线 → HTTP/2 多路复用 → HTTP/3 换 UDP,每一步只解决上一步剩下的那个阻塞。代理服务器兼具客户与服务器双重身份;条件 GET 用 If-Modified-Since 换 304,省的是实体主体不是往返。
教材出处
  • 谢希仁《计算机网络》(第 8 版)印刷 p276,6.4.3 节:「协议 HTTP 定义了浏览器(即万维网客户进程)怎样向万维网服务器请求万维网文档,以及服务器怎样把文档传送给浏览器」「HTTP 是面向事务的(transaction-oriented)应用层协议」,脚注给出事务的定义「一系列的信息交换,而这一系列的信息交换是一个不可分割的整体,也就是说,要么所有的信息交换都完成,要么一次交换都不进行」。同页:「每个万维网网点都有一个服务器进程,它不断地监听 TCP 的端口 80。」
  • 印刷 p277,6.4.3 节:无连接与无状态的两段原文——「HTTP 使用了面向连接的 TCP 作为运输层协议,保证了数据的可靠传输……但是,协议 HTTP 本身是无连接的。这就是说,虽然 HTTP 使用了 TCP 连接,但通信的双方在交换 HTTP 报文之前不需要先建立 HTTP 连接」;「协议 HTTP 是无状态的(stateless)……HTTP 的无状态特性简化了服务器的设计,使服务器更容易支持大量并发的 HTTP 请求」。同页还有本篇第四节的地基:「当建立 TCP 连接的三报文握手的前两个报文完成后(即经过了一个 RTT 时间后),万维网客户就把 HTTP 请求报文,作为建立 TCP 连接的三报文握手中的第三个报文的数据,发送给万维网服务器」,结论是「请求一个万维网文档所需的时间是该文档的传输时间(与文档大小成正比)加上两倍往返时间 RTT」。
  • 印刷 p278,6.4.3 节:非持久的两项代价——「每一次链接下载都导致 2×RTT 的开销。另一种开销就是万维网客户和服务器每一次建立新的 TCP 连接都要分配缓存和变量」「好在浏览器都能够打开 5~10 个并行的 TCP 连接」。持久连接的定义与两种工作方式:「非流水线方式的特点,是客户在收到前一个响应后才能发出下一个请求……客户每访问一次对象都要用去一个往返时间 RTT。这比非持续连接要用去两倍 RTT 的开销,节省了建立 TCP 连接所需的一个 RTT 时间」;「流水线方式的特点,是客户在收到 HTTP 的响应报文之前就能够接着发送新的请求报文……使用流水线方式时,客户访问所有的对象只需花费一个 RTT 时间」。HTTP/2 的三点改进与队头阻塞描述也在本页:「但服务器发回响应时必须按先后顺序排队,逐个地发送给客户。有时遇到某个响应迟迟不能发回,那么排在后面的一些响应就必须等待很长的时间。HTTP/2 把服务器发回的响应变成可以并行地发回(使用同一个 TCP 连接)」。
  • 印刷 p279,6.4.3 节 2. 代理服务器:「代理服务器(proxy server)是一种网络实体,它又称为万维网高速缓存(Web cache)。代理服务器把最近的一些请求和响应暂存在本地磁盘中。」以及代理访问互联网的五个步骤。
  • 印刷 p280:「代理服务器有时是作为服务器(当接受浏览器的 HTTP 请求时),但有时却作为客户(当向互联网上的源点服务器发送 HTTP 请求时)」,以及 CDN 的定义。同页 3. HTTP 的报文结构:请求报文与响应报文「这两种报文格式的区别就是开始行不同」,「由于 HTTP 是面向文本的,因此在报文中的每一个字段都是一些 ASCII 码串,因而各个字段的长度都是不确定的」。

说明:折叠块里的 RTT、链路速率与文件大小均为自造数据;能与教材对账的是四个 RTT 计数公式的依据(非持久每对象 2 RTT、持久非流水线每对象 1 RTT、持久流水线所有对象共 1 RTT),已核对印刷 p277–p278 原文。HTTP/3 与 QUIC 一段在教材第 8 版正文中未展开,本篇只写到"换用 UDP 以避开 TCP 的按序交付约束"这一层,不展开 QUIC 细节。

相关知识

WWW 万维网DNS 域名系统TCP 连接管理数据包的网络之旅网络应用模型FTP 与 DHCP

真题练习