HTTP 详解:一次请求背后发生了什么?
在 Web 开发中,HTTP 几乎无处不在。
浏览器访问一个页面,前端调用一个 API,PHP、Java、Go 服务之间进行 RPC,下载文件,提交表单,这些场景背后都可能使用 HTTP。
但很多开发者真正理解的 HTTP 只是:
GET /users
POST /login
200 OK
Content-Type: application/json
如果继续往下追问:
浏览器输入一个 URL 后,到底发生了什么?
就会涉及 DNS、TCP、TLS、HTTP、连接复用、请求报文、响应报文、缓存等多个环节。
理解这些内容之后,很多常见问题都会变得容易:
为什么第一次请求比较慢?
为什么 HTTP/1.1 需要 Keep-Alive?
HTTP/2 为什么能够同时处理多个请求?
Cookie 和 Session 到底是什么关系?
304 是什么意思?
为什么 API 经常返回 401、403、404、409?
HTTPS 到底保护了什么?
HTTP 和 Socket、TCP 又是什么关系?
本文从一次实际请求开始,把这些概念串起来。
1. HTTP 到底是什么?
HTTP(Hypertext Transfer Protocol,超文本传输协议)是一个应用层的请求/响应协议。
它的核心模型非常简单:
Client
│
│ HTTP Request
▼
Server
│
│ HTTP Response
▼
Client
客户端发送 Request,服务端返回 Response。
例如:
GET /users/1001 HTTP/1.1
Host: example.com
Accept: application/json
服务器可能返回:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 35
{"id":1001,"name":"Tom","age":18}
HTTP 本身并不负责:
DNS 解析
TCP 连接建立
IP 路由
数据包传输
TLS 加密
这些属于 HTTP 下面的网络层、传输层以及安全协议。
可以简单理解为:
应用
│
│ HTTP
▼
TCP / QUIC
│
│ IP
▼
网络
HTTP 规范目前将语义与不同版本的报文表达方式分开定义。核心语义由 RFC 9110 定义,HTTP/1.1、HTTP/2 分别由 RFC 9112 和 RFC 9113 定义。
2. 输入一个 URL 后发生了什么?
假设浏览器访问:
https://example.com/users/1001
简化之后,可以理解为:
浏览器
│
├─ 1. DNS:example.com → IP
│
├─ 2. 建立 TCP 连接
│
├─ 3. TLS 握手
│
├─ 4. 发送 HTTP 请求
│
├─ 5. 服务端处理请求
│
├─ 6. 返回 HTTP 响应
│
└─ 7. 浏览器解析响应
如果使用 HTTP/1.1,典型情况下可以理解为:
DNS
↓
TCP
↓
TLS
↓
HTTP
如果是 HTTP/3,则底层传输机制不同,它使用 QUIC,而不是 TCP。
因此不要把:
HTTPS = HTTP + TCP
当成严格定义。
更准确地说:
HTTP
├── HTTP/1.1 → 通常基于 TCP
├── HTTP/2 → 基于 TCP
└── HTTP/3 → 基于 QUIC/UDP
HTTP/3 的核心变化并不是重新定义 HTTP 语义,而是改变底层传输方式。
3. HTTP 请求和响应是什么?
HTTP 最核心的两个东西就是:
Request
Response
3.1 HTTP 请求
一个典型的 HTTP/1.1 请求:
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer xxx
Content-Length: 28
{"name":"Tom","age":18}
可以拆成:
请求方法
↓
POST
请求目标
↓
/api/users
协议版本
↓
HTTP/1.1
请求头
↓
Host
Content-Type
Authorization
Content-Length
请求内容
↓
JSON Body
其中:
Method
表示客户端希望对目标资源执行什么语义。
常见方法:
| Method | 常见用途 |
|---|---|
| GET | 获取资源 |
| POST | 创建资源或执行操作 |
| PUT | 整体更新资源 |
| PATCH | 部分更新资源 |
| DELETE | 删除资源 |
| HEAD | 获取与 GET 类似的元信息,但不返回内容 |
| OPTIONS | 获取通信选项 |
例如:
GET /users/1001
表示获取用户。
而:
DELETE /users/1001
表示删除用户。
需要注意,HTTP Method 不只是字符串名称,它本身具有协议定义的语义,例如安全性(safe)和幂等性(idempotent)等。
3.2 URI
例如:
https://example.com/users/1001?page=2
可以拆成:
scheme
↓
https
host
↓
example.com
path
↓
/users/1001
query
↓
?page=2
HTTP 使用 URI 来标识请求目标资源,而 Method 决定对资源执行什么操作。
3.3 Header
Header 用于传递各种元数据。
例如:
Content-Type: application/json
Accept: application/json
Authorization: Bearer xxx
User-Agent: Mozilla/5.0
Cache-Control: no-cache
常见 Header 可以简单分成几类:
请求相关
├── Host
├── Authorization
├── User-Agent
├── Accept
└── Cookie
内容相关
├── Content-Type
├── Content-Length
└── Content-Encoding
缓存相关
├── Cache-Control
├── If-None-Match
└── If-Modified-Since
响应相关
├── Location
├── Set-Cookie
├── ETag
└── Vary
Header 是 HTTP 可扩展性的一个重要组成部分。
3.4 Body
Body 用于承载请求或响应的数据。
例如:
{
"username": "tom",
"password": "123456"
}
Body 本身并没有固定格式。
可以是:
JSON
Form
XML
HTML
图片
文件
二进制数据
具体如何解释,通常通过:
Content-Type
告诉对方。
例如:
Content-Type: application/json
表示:
Body 是 JSON
4. HTTP 响应和状态码
服务端处理请求之后,会返回 Response:
HTTP/1.1 200 OK
Content-Type: application/json
{"id":1001,"name":"Tom"}
响应最重要的是:
状态码
Header
Body
4.1 2xx:成功
常见:
200 OK
201 Created
202 Accepted
204 No Content
例如创建用户:
HTTP/1.1 201 Created
表示资源已经创建。
4.2 3xx:重定向或缓存相关
常见:
301 Moved Permanently
302 Found
304 Not Modified
307 Temporary Redirect
308 Permanent Redirect
其中 304 Not Modified 非常重要。
它并不是:
请求失败
而是告诉客户端:
你之前缓存的内容仍然有效,可以继续使用。
4.3 4xx:客户端请求存在问题
常见:
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
405 Method Not Allowed
409 Conflict
422 Unprocessable Content
429 Too Many Requests
尤其容易混淆:
401 ≠ 403
通常可以理解为:
401:当前请求缺少有效认证凭据
403:服务器理解了请求,但拒绝执行
例如 API:
没有 Token
↓
401
Token 有效,但没有权限
↓
403
4.4 5xx:服务器端错误
常见:
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
在微服务架构中:
Client
↓
Nginx
↓
Gateway
↓
Service A
↓
Service B
如果 Service A 调用 Service B 超时,就可能最终表现为:
504 Gateway Timeout
因此 HTTP 状态码不一定意味着错误直接发生在当前这一层。
5. HTTP/1.1 为什么需要 Keep-Alive?
早期 HTTP 通信可以简单理解成:
建立连接
↓
发送请求
↓
返回响应
↓
关闭连接
如果一个网页需要请求:
HTML
CSS
JS
图片
接口
每一个请求都重新建立连接,会产生大量连接建立开销。
因此 HTTP/1.1 支持持久连接。
可以理解为:
TCP Connection
│
├── HTTP Request 1
├── HTTP Response 1
│
├── HTTP Request 2
├── HTTP Response 2
│
├── HTTP Request 3
├── HTTP Response 3
│
└── ...
这样 TCP 连接可以被重复利用。
HTTP/1.1 的连接管理和消息解析由 RFC 9112 定义,其中包括持久连接以及消息长度、Chunked Transfer 等机制。
Chunked Transfer
当服务端无法提前知道完整响应长度时,可以使用:
Transfer-Encoding: chunked
例如:
chunk 1
chunk 2
chunk 3
...
服务端可以边生成数据边发送。
这在:
大文件
流式响应
动态内容
等场景比较有意义。
需要注意:
Content-Length
和:
Transfer-Encoding: chunked
是 HTTP/1.1 消息 framing 中不同的机制,不应该简单理解成“一个是普通传输,一个是流式传输”。
6. HTTP/2 解决了什么问题?
HTTP/1.1 的一个典型限制是:
一个连接
↓
多个请求
↓
请求之间存在排队和阻塞问题
HTTP/2 对 HTTP 的“线上表达方式”进行了重大改进。
核心特性包括:
二进制分帧
多路复用
Header 压缩
6.1 二进制分帧
HTTP/1.1 的消息格式具有明显的文本结构。
HTTP/2 则把通信拆成二进制 Frame。
大致可以理解:
HTTP Message
↓
Stream
↓
多个 Frame
6.2 多路复用
这是 HTTP/2 最重要的特性之一。
HTTP/1.1:
Connection
│
├── Request A
├── Response A
├── Request B
└── Response B
HTTP/2:
一个 TCP 连接
│
├── Stream 1
│ ├── Frame
│ └── Frame
│
├── Stream 3
│ ├── Frame
│ └── Frame
│
└── Stream 5
├── Frame
└── Frame
多个 HTTP 请求可以在同一个连接中并发交错传输。
因此:
HTTP/1.1
多个请求 → 多连接/排队
HTTP/2
多个请求 → 一个连接中的多个 Stream
HTTP/2 规范明确将多路复用和字段压缩作为降低延迟、提高网络资源利用率的重要机制。
不过需要注意一个容易被忽略的问题:
HTTP/2 并没有消除 TCP 本身的队头阻塞问题。
因为多个 HTTP/2 Stream 最终仍然共享 TCP 字节流。
HTTP/3 使用 QUIC 后,在传输层进一步改变了这一点。
因此可以粗略理解为:
HTTP/1.1
↓
多个 HTTP 请求
HTTP/2
↓
多个 Stream
↓
共享 TCP
HTTP/3
↓
多个 Stream
↓
QUIC
↓
UDP
7. Cookie、Session 和 HTTP 缓存
HTTP 的一个重要特点是:
HTTP 本身是无状态的。
也就是说,服务器不能仅仅根据:
TCP Connection
就假设两个请求一定来自同一个用户。
因此 Web 应用需要额外机制维护状态。
Cookie
服务端可以通过:
Set-Cookie: session_id=abc123
告诉浏览器保存 Cookie。
之后浏览器请求时:
Cookie: session_id=abc123
于是服务器就可以根据这个标识找到对应 Session。
简单理解:
第一次请求
Client ────────> Server
Set-Cookie
Client <──────── Server
后续请求
Cookie
Client ────────> Server
Cookie 本质上是 HTTP 状态管理机制的一部分,并不是 Session 本身。经典 Cookie 规范 RFC 6265 定义了 Cookie 和 Set-Cookie 的基本机制。
实际开发中还需要关注:
HttpOnly
Secure
SameSite
Domain
Path
Expires / Max-Age
例如:
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax
Session
Session 通常是服务端维护的状态:
Cookie
↓
session_id
↓
Server
↓
Session Data
例如:
session_id = abc123
Server:
abc123 → user_id=1001
所以:
Cookie ≠ Session
Cookie 是客户端保存并回传的数据。
Session 是应用服务端维护的会话状态。
现代 API 也可能采用:
Authorization: Bearer <token>
而不是传统 Session。
HTTP Cache
HTTP 缓存可以让客户端、代理服务器等复用之前的响应,从而减少网络请求和服务器压力。
例如:
第一次请求
Client ───────> Server
<────── Response
保存缓存
第二次请求
Client ───────> Cache
<────── Cached Response
或者通过条件请求:
If-None-Match: "abc123"
服务端发现资源没有变化:
HTTP/1.1 304 Not Modified
客户端继续使用已有缓存。
HTTP 缓存机制由 RFC 9111 定义,其中包括 Cache-Control、验证以及缓存复用等规则。
后端开发中经常见到:
Cache-Control: max-age=3600
ETag: "abc123"
Last-Modified: ...
这些 Header 并不是“浏览器自己的缓存功能”,而是 HTTP 标准定义的一套缓存控制机制。
8. HTTP、Socket、TCP、HTTPS、WebSocket 到底是什么关系?
这几个概念经常混在一起,可以从层次上理解。
应用
│
├── HTTP
├── WebSocket
└── 其他应用层协议
│
▼
Socket API
│
▼
TCP
│
▼
IP
但需要注意:
Socket 不是协议。
Socket 更像是应用程序访问网络通信能力的一种接口/抽象。
例如:
PHP
Java
Go
C
都可以通过 Socket API 使用 TCP/UDP 网络能力。
HTTP 则是建立在这些网络能力之上的应用层协议。
HTTPS
HTTPS 可以简单理解成:
HTTP
+
TLS
TLS 负责:
加密
完整性保护
身份认证
所以:
HTTP
↓
TLS
↓
TCP
↓
IP
HTTPS 并不是一个完全不同于 HTTP 的应用层协议。
它主要是在 HTTP 与传输层之间增加了安全保护。
WebSocket
WebSocket 也是应用层协议。
它与 HTTP 有一个非常重要的区别:
HTTP
Client → Request
Server → Response
WebSocket
Client ⇄ Server
建立连接之后,可以进行持续的双向通信。
因此非常适合:
在线聊天
实时通知
实时协作
游戏
行情推送
9. 后端开发中如何理解一次 HTTP 请求?
作为后端开发者,可以把一次 API 请求抽象成:
Client
│
│ DNS
▼
IP
│
│ TCP / QUIC
▼
Load Balancer / Nginx
│
│ HTTP
▼
Application
│
├── Router
├── Middleware
├── Authentication
├── Controller
├── Service
├── Database
└── Redis
│
▼
HTTP Response
例如:
POST /api/orders
Authorization: Bearer xxx
Content-Type: application/json
{
"product_id": 1001,
"quantity": 2
}
服务端可能经历:
Nginx
↓
HTTP Server
↓
Router
↓
Auth Middleware
↓
Controller
↓
Order Service
↓
MySQL
↓
Redis
↓
Response
最后:
HTTP/1.1 201 Created
Content-Type: application/json
{
"id": 10001,
"status": "created"
}
因此,学习 HTTP 的真正目的并不是记住大量 Header。
而是建立这样一条完整链路:
URL
↓
DNS
↓
TCP / QUIC
↓
TLS
↓
HTTP Request
↓
Web Server
↓
Application
↓
HTTP Response
↓
Browser / Client
当线上出现问题时,就可以逐层排查:
域名解析问题?
↓
TCP 连接问题?
↓
TLS 握手问题?
↓
HTTP 请求问题?
↓
网关问题?
↓
应用问题?
↓
数据库问题?
↓
响应问题?
这比单纯看到:
502
504
500
然后直接修改代码有效得多。
10. 总结
HTTP 是 Web 世界最核心的应用层协议之一,它采用请求/响应模型,并通过 Method、URI、Header、Body、Status Code 等元素表达通信语义。
从整体链路来看:
浏览器
↓
DNS
↓
TCP / QUIC
↓
TLS(HTTPS)
↓
HTTP
↓
Web Server
↓
Application
↓
HTTP Response
HTTP/1.1 重点解决了持久连接、消息传输和连接管理等问题;HTTP/2 进一步引入二进制分帧、多路复用和 Header 压缩;HTTP/3 则使用 QUIC 改变底层传输方式。
几个容易混淆的概念,可以最后再记一次:
TCP
→ 可靠的字节流传输
Socket
→ 应用程序访问网络通信的接口/抽象
HTTP
→ 应用层请求/响应协议
HTTPS
→ HTTP + TLS 安全保护
Cookie
→ 客户端保存并回传的状态信息
Session
→ 服务端维护的会话状态
HTTP/2
→ HTTP 语义 + 二进制分帧/多路复用等机制
HTTP/3
→ HTTP 语义 + QUIC 传输
真正理解 HTTP 后,再去学习 Nginx、API 网关、REST API、RPC、微服务、WebSocket、CDN 和浏览器网络性能优化,会容易很多。
另一篇 《HTTPS 详解:TLS 如何保护 HTTP 通信》