📚 全栈开发学习系列 · 阶段二(Web 全栈)
09 HTML 基础:网页骨架与语义化标签 ✅
10 CSS 基础:样式、布局与响应式 ✅
11 JavaScript 基础:变量、DOM 与事件 ✅
12 HTTP 协议基础:请求、响应与状态码(当前篇)
13 FastAPI 入门:构建第一个 RESTful API
14 PostgreSQL 基础:数据库设计与 SQL 操作
15 认证授权:JWT、Session 与 Cookie
16 综合实战:带登录的博客系统

HTTP 协议基础:请求、响应与状态码

难度:基础 | 前端三剑客集齐后,正式跨入后端领域——理解浏览器与服务器之间的通信协议
读完本篇你将能:拆解一个 URL 的每个组成部分,读懂 HTTP 请求和响应的原始报文结构,区分 GET/POST/PUT/DELETE 的使用场景,通过状态码判断请求结果,用 curl 命令行手动发送请求并查看完整响应,理解 HTTP/1.1 到 HTTP/3 的演进脉络。
📑 本文目录
01HTTP 初识:互联网的通信规则
02HTTP 请求:方法与结构
03HTTP 响应:状态码与结构
04HTTP 头部:请求与响应的元数据
05实战:curl 命令行发送请求
06实战:浏览器 DevTools 抓包分析
07HTTP 版本演进(1.1 → 2 → 3)

01 HTTP 初识:互联网的通信规则

前十一篇里,你写了 HTML 定义内容、CSS 控制样式、JavaScript 添加交互——这些都在浏览器里完成。但真实的 Web 应用中,数据存在服务器上,浏览器需要通过网络向服务器"索要"数据。这套通信规则就是 HTTP(HyperText Transfer Protocol,超文本传输协议)。

把 HTTP 想象成一套邮政系统:浏览器是寄信人(客户端),服务器是邮局加收信人。寄信人按固定格式写好信封(请求),投入邮筒;邮局根据地址找到收信人,收信人处理后写一封回信(响应),原路返回。信封上的邮编、加急标记对应 HTTP 头部,信件内容对应请求体,回执单上的签收状态对应状态码——200 签收成功,404 查无此人,500 邮局内部出错。

请求-响应模型

HTTP 采用严格的"一问一答"模型:客户端发起一个请求,服务器返回一个响应。没有请求就没有响应——服务器不会主动推送数据(WebSocket 和 Server-Sent Events 是另外的协议,后续篇章涉及)。

浏览器(客户端)
→ 请求 →
服务器
← 响应 ←
浏览器(客户端)

URL 的结构

URL(Uniform Resource Locator,统一资源定位符)就是信封上的地址——告诉 HTTP 该把请求送到哪里。一个完整的 URL 包含多个组成部分:

URL 结构
https://api.example.com:443/users?page=1&limit=10#profile
│ │ │ │ │ │
│ │ │ │ │ └ 锚点(fragment)
│ │ │ │ └ 查询参数(query)
│ │ │ └ 路径(path)
│ │ └ 端口(port,HTTPS默认443)
│ └ 主机名(host)
• scheme:协议名,常见 http 或 https(加密版)
• host:服务器域名或 IP 地址,如 api.example.com
• port:端口号,HTTP 默认 80,HTTPS 默认 443,默认端口可省略
• path:资源路径,如 /users 表示用户列表资源
• query:查询参数,?page=1&limit=10 用 & 分隔多组键值对
💡 小贴士
URL 中的查询参数(query string)是 GET 请求传递数据的主要方式。参数顺序不影响结果,?page=1&limit=10 和 ?limit=10&page=1 效果相同。但参数值包含特殊字符(如 &、=、中文)时必须进行 URL 编码,否则服务器解析会出错。

02 HTTP 请求:方法与结构

理解了 URL 这个"地址",接下来看信件本身。一个 HTTP 请求由四部分组成:请求行、请求头、空行、请求体。下面是一个真实的 GET 请求原始报文:

HTTP Request
GET /api/users?page=1 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0 (Macintosh)
Accept: application/json
(空行——标志请求头结束,下面是请求体)
(GET 请求通常没有请求体)

第一行是请求行,包含三部分:请求方法(GET)、请求路径(/api/users?page=1)、协议版本(HTTP/1.1),用空格分隔。后面几行是请求头,每行一个键值对。空行之后是请求体——GET 请求通常没有body,数据放在 URL 的查询参数里。

五种常见 HTTP 方法

请求方法就是"信件类型"——平信、挂号信、快递各有不同用途。HTTP 定义了多种方法,日常开发最常用的有五种:

方法 含义 有请求体 典型场景
GET 获取资源 否 打开网页、查询列表
POST 创建资源 是 提交注册表单、发布文章
PUT 替换资源(整体更新) 是 更新用户完整信息
PATCH 修改资源(部分更新) 是 只改用户昵称
DELETE 删除资源 通常否 删除文章、注销账号

POST 请求的请求体通常携带用户提交的数据。下面是一个 POST 请求的原始报文,注意请求体中的 JSON 数据:

HTTP Request (POST)
1
2
3
4
5
6
7
8
9
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 52
(空行)
(请求体开始)
{
  "name": "张三", "email": "zhang@example.com"

Content-Type: application/json 告诉服务器请求体的格式是 JSON。Content-Length: 52 表示请求体有 52 字节。服务器读取完 52 字节后就知道请求体结束了。

03 HTTP 响应:状态码与结构

请求寄出去了,服务器处理完会回一封信——HTTP 响应。结构和请求类似,也分四部分:状态行、响应头、空行、响应体。关键区别在第一行:请求行变成了状态行,包含状态码和状态描述。

HTTP Response
1
2
3
4
5
6
7
8
9
10
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 87
Date: Tue, 12 Aug 2026 10:30:00 GMT
(空行)
{
  "id": 1,
  "name": "张三",
  "email": "zhang@example.com"

第一行 HTTP/1.1 200 OK 是状态行:协议版本、状态码(200)、状态描述(OK)。状态码是回执单上最重要的信息——一眼就知道请求成功了没有。

状态码五大类别

范围 类别 含义
1xx 信息性 请求已接收,继续处理(少见)
2xx 成功 请求被成功接收和处理
3xx 重定向 需要进一步操作才能完成请求
4xx 客户端错误 请求有语法错误或无法完成
5xx 服务器错误 服务器处理时出错

常见状态码速查

状态码 描述 真实含义
200 OK 请求成功,响应体包含数据
201 Created POST 创建资源成功
204 No Content 成功但无返回内容(DELETE 常用)
301 Moved Permanently 资源永久重定向到新地址
304 Not Modified 资源未修改,用浏览器缓存即可
400 Bad Request 请求语法错误(如 JSON 格式不对)
401 Unauthorized 未登录,需要身份认证
403 Forbidden 已登录但无权限访问该资源
404 Not Found 请求的资源不存在
500 Internal Server Error 服务器代码崩溃或出错
502 Bad Gateway 网关/代理从上游收到无效响应
503 Service Unavailable 服务器过载或维护中,暂不可用
⚠️ 常见错误
看到 401 就以为是"没权限" — 401 是"未认证"(没登录),403 才是"没权限"(登录了但角色不够)。区分清楚才能在代码中返回正确的状态码。
✓ 正确:未登录访问 → 返回 401;已登录但非管理员 → 返回 403

04 HTTP 头部:请求与响应的元数据

请求和响应都携带"头部"——相当于信封上的附加信息。头部是键值对形式,每行一个,用冒号分隔。它告诉对方"我是谁""我要什么格式""数据有多长"等元信息。掌握常用头部是调试网络问题的基本功。

常见请求头

请求头 作用 示例值
Host 目标服务器域名 api.example.com
Content-Type 请求体的数据格式 application/json
Authorization 身份认证凭证 Bearer eyJhbGc...
Accept 期望的响应格式 application/json, */*
User-Agent 客户端身份标识 Mozilla/5.0 (Macintosh)

常见响应头

响应头 作用 示例值
Content-Type 响应体的数据格式 application/json; charset=utf-8
Content-Length 响应体字节数 87
Set-Cookie 设置 Cookie(后续篇章详解) session=abc123; HttpOnly
Cache-Control 缓存策略指令 max-age=3600
Location 重定向目标地址(3xx 配合) /users/1
💡 小贴士
Content-Type 是前后端协作中最容易出问题的头部。前端发 JSON 但没设 Content-Type: application/json,后端按默认的 application/x-www-form-urlencoded 解析,结果拿到的是空数据。这是 400 Bad Request 最常见的根因之一。

05 实战:curl 命令行发送请求

浏览器帮你封装了 HTTP 请求,看不到原始报文。curl 是命令行下的 HTTP 客户端工具,macOS 和 Linux 自带,能让你手动发送请求并查看完整响应——调试 API 时比浏览器灵活得多。

GET 请求:获取数据

Shell
# 发送 GET 请求,-i 显示响应头
curl -i https://httpbin.org/get
# httpbin.org 是测试 HTTP 请求的免费服务

执行后,终端会输出完整的 HTTP 响应(包含状态行、响应头和响应体):

输出
1
2
3
4
5
6
7
8
9
10
11
12
HTTP/2 200 OK
content-type: application/json
content-length: 218
{
  "args": {},
  "headers": {
    "Host": "httpbin.org",
    "User-Agent": "curl/8.7.1"
  },
  "origin": "203.0.113.5"
}

-i 标志让 curl 输出响应头(默认只显示响应体)。httpbin.org 的 /get 端点会把收到的请求信息原样返回——你能看到服务器"收到"了哪些头部。

POST 请求:提交 JSON 数据

Shell
curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -d '{"name":"张三","age":25}'
# -X 指定方法 -H 添加请求头 -d 携带请求体

三个关键标志:-X POST 指定方法(GET 可省略,其他需显式指定)、-H 添加请求头、-d 携带请求体数据。httpbin.org 的 /post 端点会把收到的数据回显在 "json" 字段中。

curl 常用标志速查

标志 作用 示例
-X 指定 HTTP 方法 -X DELETE
-H 添加请求头 -H "Authorization: Bearer xxx"
-d 携带请求体数据 -d '{"key":"val"}'
-i 显示响应头 curl -i URL
-v 显示完整通信过程 curl -v URL
-o 输出保存到文件 -o result.json
💡 小贴士
-v(verbose)是调试 HTTP 的杀手锏——它同时显示请求头(以 > 开头)和响应头(以 < 开头),连 TLS 握手过程都能看到。遇到请求不生效时,先 curl -v 看看实际发了什么。

06 实战:浏览器 DevTools 抓包分析

curl 适合主动发起请求,但很多时候你需要观察页面加载时浏览器自动发了哪些请求——比如 AJAX 接口返回了 500,或者图片加载失败。这时用浏览器开发者工具的 Network 面板更方便。

操作步骤

1 打开任意网页(如博客首页),按 F12 或 Cmd+Option+I(Mac)打开开发者工具
2 切换到 Network(网络)标签页
3 刷新页面(Cmd+R),Network 面板会列出所有 HTTP 请求
4 点击列表中任意一条请求,右侧弹出详情面板
5 在详情面板中查看 Headers(请求头+响应头)、Response(响应体原始内容)

Network 面板的关键信息列:

列名 显示内容
Name 请求的文件名或路径
Status 状态码(200/304/404 等)
Type 资源类型(document/js/css/xhr/img)
Size 传输大小(显示"from cache"表示走了缓存)
Time 请求耗时(毫秒)
⚠️ 常见错误
Network 面板是空的,以为页面没有发请求 — 面板只在打开状态下记录请求。如果你先打开网页再开 Network,之前的请求不会被记录。
✓ 正确:先打开 DevTools → 切到 Network → 再刷新页面,这样才能捕获全部请求。

07 HTTP 版本演进(1.1 → 2 → 3)

HTTP 协议从 1991 年诞生至今经历了多次迭代。理解版本差异不需要深入细节,但知道每个版本解决了什么问题,有助于你在面试和性能优化时做出正确判断。

版本 年份 核心改进 传输层
HTTP/1.1 1997 持久连接(Keep-Alive),管线化 TCP
HTTP/2 2015 多路复用、头部压缩、服务器推送 TCP
HTTP/3 2022 基于 QUIC 协议,解决队头阻塞 UDP

HTTP/1.1 的核心问题是队头阻塞:一个 TCP 连接上多个请求必须按顺序处理,前面的慢了后面的全等。浏览器为了绕过这个限制,会对同一域名开 6 个并行连接,但每个连接仍存在队头阻塞。

HTTP/2 引入多路复用——一个 TCP 连接上同时跑多个请求/响应,互不阻塞。还加了 HPACK 头部压缩(减少重复头部传输量)和服务器推送(主动推送 CSS/JS 等资源)。

HTTP/3 更激进——直接抛弃 TCP,改用基于 UDP 的 QUIC 协议。TCP 层的队头阻塞在 HTTP/2 中仍存在(一个包丢了,整个连接的所有流都卡住),QUIC 在 UDP 上自己实现可靠性,每个流独立重传,彻底解决了这个问题。现代浏览器和主流 CDN 已广泛支持 HTTP/3。

💡 小贴士
实际开发中你不需要关心用的是哪个版本——浏览器和服务器会自动协商最高版本。但如果用 curl -v 观察请求,响应状态行可能显示 HTTP/2 200 而非 HTTP/1.1 200——说明服务器已升级到 HTTP/2。
📖 知识回顾
URL 结构 请求-响应模型 GET/POST/PUT/DELETE 请求报文四部分 状态码五大类 200/404/500 401 vs 403 Content-Type Authorization curl -i -v -H -d DevTools Network HTTP/2 多路复用
✏️ 动手练习
🟢 基础验证
请用 curl 向 https://httpbin.org/get 发送 GET 请求,并使用 -i 标志查看响应头。确认状态码是否为 200,并找到响应头中 content-type 的值。
参考命令:curl -i https://httpbin.org/get — 预期输出首行为 HTTP/2 200,content-type: application/json
🟡 组合应用
用 curl 向 https://httpbin.org/status/404 发送请求,观察返回的状态码。然后再向 https://httpbin.org/status/500 发送请求。解释这两个状态码的含义差异,以及分别属于哪个类别。
参考方向:404 属于 4xx 客户端错误(资源不存在),500 属于 5xx 服务器错误(服务器内部异常)。httpbin.org/status/{code} 会返回指定的状态码供测试用。
🔴 开放挑战
打开你常用的任意网站,用 DevTools Network 面板抓取页面加载时的所有请求。找到返回 304 Not Modified 的请求,解释为什么服务器没有返回完整内容而是 304。提示:关注请求头中的 If-None-Match 或 If-Modified-Since,以及响应头中的 ETag 或 Last-Modified,搜索关键词"HTTP 条件请求"了解原理。
下篇预告
13 FastAPI 入门:构建第一个 RESTful API
理解了 HTTP 协议的请求与响应,下一步亲手搭建服务器——用 Python FastAPI 框架创建 API 端点,处理 GET/POST 请求,返回 JSON 响应,把本篇学到的 HTTP 理论变成可运行的后端代码
关注公众号 · 持续获取全栈开发学习更新