【计算基础|网络02】HTTP 原理:报文结构、方法语义与状态码

【计算基础|网络02】HTTP 原理:报文结构、方法语义与状态码

上一篇把"一次请求的全景"走完了,停在了应用层。这一篇就钻进应用层,把 HTTP 这封信本身彻底拆开。

很多人天天调接口,却说不清一个 HTTP 请求到底由几块组成;状态码背了一肚子,真遇到 422、429、504 还是发懵。根子在于:HTTP 不是什么黑盒协议,它就是一段按固定格式组织的文本。你把这封信的信封(请求行/响应行)、信纸抬头(头部)、分页线(空行)、正文(实体)看明白,方法语义和状态码就不是死记硬背,而是顺理成章。

环境:macOS 自带 curl 8.7.1,全程用 curl -v 抓真实报文;HTTP 语义以现行 RFC 9110(HTTP 语义)为准,HTTP/1.1 报文格式以 RFC 9112 为准。


一、HTTP 报文就四部分:信封、抬头、分页线、正文

结论先给:无论请求还是响应,报文都 = 起始行 + 头部区 + 空行 + 实体(可选)。请求和响应的差别只在"起始行":请求是"请求行",响应是"状态行"。

1.1 请求报文 vs 响应报文对照

http 复制代码
# ===== 请求报文 =====
GET /get?name=lonez HTTP/1.1      # ① 请求行:方法 + 路径(含查询串) + 版本
Host: httpbin.org                 # ② 头部:key: value,每行一个
User-Agent: curl/8.7.1
Accept: */*
                                  # ③ 空行:CRLF,分隔头部与实体,绝不能少
{"name":"lonez"}                  # ④ 实体(请求体):GET 一般没有,POST/PUT 才有
http 复制代码
# ===== 响应报文 =====
HTTP/1.1 200 OK                   # ① 状态行:版本 + 状态码 + 原因短语
Date: Tue, 22 Sep 2026 03:46:24 GMT   # ② 头部
Content-Type: application/json
Content-Length: 254
Connection: keep-alive
Server: gunicorn/19.9.0
                                  # ③ 空行
{"args":{}, "headers":{...}}      # ④ 实体(响应体):真正的页面/数据

对照着看就清楚了:

部分 请求报文里叫 响应报文里叫 内容
① 起始行 请求行 状态行 请求:方法 路径 版本;响应:版本 状态码 原因短语
② 头部区 请求头 响应头 一堆 key: value,描述元信息
③ 空行 空行 空行 一个 CRLF,标记头部结束
④ 实体 请求体 响应体 真正要传的数据,GET 通常无请求体

🔴 重点 :那个空行是协议的硬规定。头部和实体之间必须有一个单独的 CRLF,服务器靠它判断"头读完了,下面是体"。手搓报文时漏掉空行,服务端会一直等不到头结束、直到超时------这是 socket 手撸 HTTP 最经典的坑。

1.2 用 curl -v 抓一份真实可读的报文

光看结构不够,我们直接抓一份真实的。注意:现在很多站点默认协商成 HTTP/2,报文是二进制帧(05 篇讲),看不清。所以强制 --http1.1,把可读文本报文逼出来:

bash 复制代码
curl -sv --http1.1 https://httpbin.org/get 2>&1 | grep -E "^[*>]"

> 开头是你发出去的请求,< 开头是收到的响应,真实输出如下:

text 复制代码
* ALPN: server accepted http/1.1
* using HTTP/1.x
> GET /get HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Date: Tue, 22 Sep 2026 03:46:24 GMT
< Content-Type: application/json
< Content-Length: 254
< Connection: keep-alive
< Server: gunicorn/19.9.0
<

对照 1.1 的四部分:> GET /get HTTP/1.1 是请求行,> Host/User-Agent/Accept 是请求头,> 后面那个空行就是③,< 后面的就是响应。这就是 HTTP 的全部秘密------你写的框架、requests、浏览器,干的事就是按这个格式把文本拼好塞进 TCP。


二、请求方法语义:谁安全、谁幂等

上一篇(03 实战篇)已经用过方法,这里把语义讲透,重点是两个面试高频词:安全(Safe) 和 幂等(Idempotent)。

  • 安全:方法执行不会改变服务器资源状态,纯读。GET/HEAD/OPTIONS 安全。
  • 幂等:同一请求执行一次和执行 N 次,对服务器资源的影响相同。GET/PUT/DELETE 幂等,POST 不幂等。

2.1 方法语义对照表(RFC 9110)

方法 语义 安全 幂等 有请求体 典型场景
GET 获取资源 ✅ ✅ 否 列表、详情、搜索
HEAD 同 GET,但只要响应头不要体 ✅ ✅ 否 探活、看文件大小/更新时间
POST 新建/提交/触发一个动作 ❌ ❌ 是 新建资源、登录、下单
PUT 用载荷完整替换目标资源 ❌ ✅ 是 全量更新(不存在则创建)
PATCH 对资源做部分修改 ❌ 通常设计成幂等 是 只改某几个字段
DELETE 删除资源 ❌ ✅ 一般无 删除
OPTIONS 查询目标支持哪些方法/选项 ✅ ✅ 否 CORS 预检(04 篇讲)

🔴 为什么 GET/PUT/DELETE 幂等、POST 不幂等:

  • GET /users/100:读一次和读一百次,资源都没变。
  • DELETE /users/100:删第一次用户没了,删第一百次还是"没了"这个状态,资源状态没变(哪怕第二次返回 404)。
  • POST /orders:发一次建一个订单,发十次建十个,资源被改变十次。

这就是为什么下单接口网络抖动时不能让用户无脑重试 ------POST 不幂等,重试会重复扣款;而 GET、DELETE 重发无所谓。线上要给 POST 做"幂等键"(Idempotency-Key),本质就是把不幂等的 POST 人为设计成幂等。

⚠️ PUT vs PATCH 的坑 :PUT 是"用我给你的这份完整表示替换旧的",你得把所有字段带上,没带的字段可能被置空;PATCH 只带要改的字段。很多人全用 POST 图省事,接口可读性就没了。


三、状态码速查:三位数字的第一位是分类

结论先给:状态码三位数字,第一位定大类,后两位是具体原因。 记住五大类,剩下的就是对号入座。

大类 含义 你该怎么理解
1xx 信息性(临时响应) 握手过程中的中间状态,业务基本不碰(101 切换协议、103 早期提示)
2xx 成功 请求被正常接收、理解、处理
3xx 重定向 要进一步操作才能完成,多半是跳转或用缓存
4xx 客户端错误 你的请求有问题,服务器不处理
5xx 服务器错误 服务器自己出问题了,不是你的请求格式错

🔴 最实用的判断:4xx 怪客户端(前端/调用方改),5xx 怪服务端(后端/运维改)。看到 4xx 别急着找后端,先看自己请求发对没。

3.1 高频状态码逐个说

状态码 名称 什么时候出现 怎么处理
200 OK 请求成功 正常
201 Created POST 新建资源成功 看 Location 头拿新资源地址
204 No Content 成功但没有响应体(DELETE 常用) 别去解析 body
301 Moved Permanently 永久重定向(http→https、域名迁移) 浏览器会缓存,自动跳
302 Found 临时重定向(登录后跳回原页) 临时,不缓存
304 Not Modified 资源没变化,用本地缓存 配合 If-Modified-Since/ETag,省流量
400 Bad Request 请求本身格式错(JSON 语法错、缺参) 检查报文格式
401 Unauthorized 没登录/凭证无效 先去拿 token
403 Forbidden 已认证但没权限 权限问题,别再重试
404 Not Found 路径/资源不存在 查 URL 或资源是否被删
405 Method Not Allowed 路径对但方法不对(该用 GET 用了 POST) 换方法
415 Unsupported Media Type Content-Type 服务器不认 核对请求体格式
422 Unprocessable Entity 格式对但语义校验不过(字段类型错、缺必填) 最常见于表单/JSON 校验失败
429 Too Many Requests 触发限流了 退避重试,别狂刷
500 Internal Server Error 服务器内部炸了(代码异常) 找后端看日志
502 Bad Gateway 网关/代理从上游拿到无效响应 后端进程挂了或没起,找运维
503 Service Unavailable 服务暂时不可用(过载、维护) 稍后重试
504 Gateway Timeout 网关等上游响应超时 后端处理太慢或挂了

⚠️ 几个最容易混的:

  • 401 vs 403:401 是"你是谁我都不知道"(没带/带错凭证);403 是"我知道你是谁,但你就是没权限"。
  • 301 vs 302:301 永久,浏览器会记住、下次直接跳;302 临时。SEO 和接口迁移要分清,别把临时跳转配成 301。
  • 502 vs 504:502 是网关连上游时拿到了"坏"响应(上游进程崩了);504 是网关等上游等到超时(上游还在跑但太慢)。

3.2 实测几个真实状态码

用 httpbin 直接构造各种状态码,眼见为实:

bash 复制代码
# -o /dev/null 丢弃 body,-w 只打印状态码
curl -s -o /dev/null -w "200 -> %{http_code}\n" https://httpbin.org/get
curl -s -o /dev/null -w "404 -> %{http_code}\n" https://httpbin.org/status/404
curl -s -o /dev/null -w "401 -> %{http_code}\n" https://httpbin.org/status/401
# http 访问 github 会被 301 到 https
curl -s -o /dev/null -w "301 -> %{http_code} 跳转到 %{redirect_url}\n" http://github.com

真实输出:

text 复制代码
200 -> 200
404 -> 404
401 -> 401
301 -> 301 跳转到 https://github.com/

注意最后一行:http://github.com 返回 301 ,redirect_url 是 https://github.com/------这就是"HTTP 永久重定向到 HTTPS"的真实样子。


四、HTTP/1.0 vs HTTP/1.1:差在哪

结论先给:HTTP/1.1 相比 1.0 最大的进步是"省连接"和"更灵活"------长连接、Host 头、分块传输、范围请求。 现在说的"HTTP/1.1"就是 1997 年定稿、至今仍是基础版本的那套。

特性 HTTP/1.0 HTTP/1.1 解决了什么问题
连接 默认短连接,每个请求建一次 TCP 默认 Keep-Alive 长连接,一个连接跑多个请求 省掉反复三次握手的开销
Host 头 无(一个 IP 一个站点) 必须带 Host 一台服务器(一个 IP)靠 Host 头托管多个域名(虚拟主机)
响应体长度 靠连接关闭判断结束 Chunked 分块传输 (Transfer-Encoding: chunked) 边生成边发,不用先算好总长度
范围请求 无 Range 请求 (Range: bytes=0-1023) 断点续传、视频拖拽、只取文件一段
管线化 无 支持 Pipelining(发完一个不等响应就发下一个) 进一步省往返(但因队头阻塞基本被弃用,05 篇讲)
方法/状态码 少 更多方法(PUT/PATCH/OPTIONS)、更多状态码 语义更丰富

🔴 重点理解 Host 头 :没有 Host 头,一个 IP 只能对应一个网站;有了 Host 头,Nginx 在同一个 IP:80 上靠 Host: a.com 和 Host: b.com 区分两个站点。这也是为什么你手动 curl 一个 IP 访问虚拟主机会 404 或拿到默认站------因为没带对 Host。

⚠️ 管线化(Pipelining)为什么没普及 :它要求响应必须按请求顺序返回(队头阻塞),第一个响应慢,后面全堵着。实际实现问题太多,浏览器基本默认关掉,直到 HTTP/2 才真正解决。这正是 05 篇的主线。

4.1 常用请求头/响应头速查

头部 方向 作用
Host 请求 目标主机名(+端口),虚拟主机靠它
User-Agent 请求 客户端身份(浏览器/脚本/SDK)
Accept 请求 我能接收什么类型的响应(application/json、*/*)
Content-Type 请求/响应 实体是什么格式(json/form/multipart)
Content-Length 请求/响应 实体字节长度
Connection 请求/响应 keep-alive / close,控制连接是否复用
Accept-Encoding 请求 我支持的压缩(gzip/br)
Content-Encoding 响应 响应实体实际用的压缩算法
Authorization 请求 鉴权凭证(Bearer/ Basic)
Cookie 请求 携带会话 Cookie
Server 响应 服务器软件(gunicorn/nginx)
Location 响应 重定向去哪(3xx 必带)
Set-Cookie 响应 让客户端种下 Cookie
Transfer-Encoding 响应 chunked,分块传输
Range / Content-Range 请求/响应 范围请求、断点续传
ETag / If-None-Match 响应/请求 缓存校验(配合 304)

🔴 分清两对 :Accept(我要什么)vs Content-Type(这是什么);Accept-Encoding(我支持什么压缩)vs Content-Encoding(实际用了什么压缩)。方向别搞反。


五、把这些串起来:一次完整报文长什么样

把前面所有点拼起来,一个带 JSON body 的 POST 真实请求/响应报文骨架:

http 复制代码
POST /users HTTP/1.1              # 请求行
Host: api.example.com             # 头部开始
Content-Type: application/json
Content-Length: 38
Authorization: Bearer eyJhbGci...
                                  # 空行
{"name":"lonez","age":25}        # 请求体
http 复制代码
HTTP/1.1 201 Created             # 状态行
Content-Type: application/json
Content-Length: 42
Location: /users/1001
Connection: keep-alive
                                  # 空行
{"id":1001,"name":"lonez"}       # 响应体

方法语义(POST 新建→201)、状态码(201 Created)、头部(Location 指向新资源)、四部分结构,全对上了。


总结:你真正需要记住的 8 件事

  1. 报文 = 起始行 + 头部 + 空行 + 实体;请求的起始行叫请求行,响应的叫状态行。
  2. 空行是硬规定,漏了服务端会一直等头结束直到超时。
  3. 安全 (只读)和幂等(执行一次和 N 次效果相同)是两个独立维度;GET/PUT/DELETE 幂等,POST 不幂等。
  4. POST 不幂等,所以下单不能无脑重试,要靠幂等键。
  5. 状态码第一位定大类:2xx 成功、3xx 重定向、4xx 客户端错、5xx 服务端错。
  6. 高频码要能反应:401 没登录、403 没权限、422 语义校验失败、429 限流、502 上游挂、504 上游超时。
  7. HTTP/1.1 相对 1.0:默认 Keep-Alive 长连接、必须带 Host 头、Chunked 分块、Range 范围请求。
  8. 看真实报文用 curl -v --http1.1(强制文本报文),> 是请求、< 是响应。

验证清单

  • 能默写出请求/响应报文的四部分,并说清空行的作用
  • 能用 curl -v --http1.1 抓一份真实报文,指出每一行属于哪一部分
  • 能说清安全/幂等的区别,以及为什么 POST 不幂等、DELETE 幂等
  • 能区分 401/403、301/302、502/504
  • 能说出 HTTP/1.1 相对 1.0 的四个关键改进
  • 理解为什么必须带 Host 头,以及不带会怎样
  • 能说出至少 6 个常用请求头和它们的方向
  • 用 curl -o /dev/null -w "%{http_code}" 实测过 200/301/404/401

参考资源


下一篇《网络05:HTTP/1.1 优化、HTTP/2 与 HTTP/3》:接着这篇讲"文本报文太啰嗦、长连接队头阻塞"是怎么一步步逼出 HTTP/2 的二进制分帧、多路复用、HPACK,又怎么因为 TCP 层队头阻塞最终走向 HTTP/3 与基于 UDP 的 QUIC,并实测用 curl --http2 验证真实协商结果。

相关推荐
搁浅小泽1 小时前
新能源汽车多合一压缩机控制器LIN网络测试规范
网络·汽车
可乐鸡翅yeah_2 小时前
HLS 业务 Referer‑Policy 网页元标签引发播放异常排错
前端·javascript·网络·ffmpeg·php·音视频
河北清兮网络科技2 小时前
直播APP商用开发深度解析:为什么模板系统无法支撑规模化直播平台
运维·网络·人工智能·小程序·短剧app
月落汀兰2 小时前
为什么跨网桥容器 ping 不通?Docker 网络模式详解,端口映射、容器访问外网底层实战
网络·docker·容器
运维行者_2 小时前
PHP性能监控怎么做?从响应时间到慢函数的6个关键指标
运维·服务器·开发语言·网络·支持向量机·php·接口隔离原则
andxe2 小时前
800G OSFP封装对比:OSFP IHS 与 RHS 封装差异
网络·光模块·光通信
Multipath7123 小时前
无人载具的高可靠低时延聚合组网方案
网络·网络协议·安全·udp·智能路由器
当下新鲜事3 小时前
皮尔磁纸板进料安全方案怎么选:myPNOZ与O300组合使用经验分享
网络·人工智能·安全
雪雪爱冲浪3 小时前
ISP代理与住宅代理选型对比:从原理到实战
服务器·网络·网络协议·tcp/ip·接口隔离原则