HTTP 协议详解教程 / 第 2 章:HTTP 基础要素
第 2 章:HTTP 基础要素
本章将系统介绍 HTTP 协议的四大基本构件:请求方法、状态码、头部字段和消息结构。这些是理解后续所有章节的基石。
2.1 HTTP 消息结构
HTTP 通信的基本单位是 消息(Message),分为 请求消息 和 响应消息。
请求消息(Request)
┌─────────────────────────────────────┐
│ 请求行 (Request Line) │ METHOD SP URI SP VERSION CRLF
├─────────────────────────────────────┤
│ 请求头部 (Request Headers) │ Header-Name: value CRLF
│ ... │
├─────────────────────────────────────┤
│ 空行 (Blank Line) │ CRLF
├─────────────────────────────────────┤
│ 请求体 (Request Body) │ 可选
└─────────────────────────────────────┘
实际示例:
POST /api/users HTTP/1.1\r\n
Host: api.example.com\r\n
Content-Type: application/json\r\n
Content-Length: 48\r\n
Authorization: Bearer eyJhbG...\r\n
\r\n
{"name":"Alice","email":"alice@example.com"}
响应消息(Response)
┌─────────────────────────────────────┐
│ 状态行 (Status Line) │ VERSION SP STATUS SP REASON CRLF
├─────────────────────────────────────┤
│ 响应头部 (Response Headers) │ Header-Name: value CRLF
│ ... │
├─────────────────────────────────────┤
│ 空行 (Blank Line) │ CRLF
├─────────────────────────────────────┤
│ 响应体 (Response Body) │ 可选
└─────────────────────────────────────┘
实际示例:
HTTP/1.1 201 Created\r\n
Content-Type: application/json\r\n
Location: /api/users/123\r\n
Content-Length: 62\r\n
\r\n
{"id":123,"name":"Alice","email":"alice@example.com"}
用 Python 手动构建 HTTP 消息
import socket
def raw_http_request():
"""手动构建 HTTP 请求,理解底层格式"""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("httpbin.org", 80))
# 手动构建请求文本
request = (
"GET /get HTTP/1.1\r\n"
"Host: httpbin.org\r\n"
"User-Agent: raw-python/1.0\r\n"
"Accept: application/json\r\n"
"Connection: close\r\n"
"\r\n"
)
sock.send(request.encode())
# 接收响应
response = b""
while True:
data = sock.recv(4096)
if not data:
break
response += data
sock.close()
print(response.decode())
raw_http_request()
2.2 请求方法(Request Methods)
HTTP 定义了一组 请求方法,指示对资源要执行的操作。
核心方法总览
| 方法 | 语义 | 有请求体 | 有响应体 | 安全 | 幂等 |
|---|---|---|---|---|---|
| GET | 获取资源 | ✗ | ✓ | ✓ | ✓ |
| POST | 提交数据/创建资源 | ✓ | ✓ | ✗ | ✗ |
| PUT | 替换/创建资源 | ✓ | ✓ | ✗ | ✓ |
| DELETE | 删除资源 | ✗ | ✓ | ✗ | ✓ |
| PATCH | 部分更新资源 | ✓ | ✓ | ✗ | ✗ |
| HEAD | 仅获取头部 | ✗ | ✗ | ✓ | ✓ |
| OPTIONS | 查询支持的方法 | ✗ | ✓ | ✓ | ✓ |
安全(Safe):不会修改服务器上的资源 幂等(Idempotent):同一请求执行多次,效果与执行一次相同
各方法的典型用法
# GET — 获取资源
curl https://api.example.com/users/1
# POST — 创建资源
curl -X POST \
-H "Content-Type: application/json" \
-d '{"name":"Bob"}' \
https://api.example.com/users
# PUT — 完整替换资源
curl -X PUT \
-H "Content-Type: application/json" \
-d '{"name":"Bob Updated","age":30}' \
https://api.example.com/users/1
# PATCH — 部分更新
curl -X PATCH \
-H "Content-Type: application/json" \
-d '{"age":31}' \
https://api.example.com/users/1
# DELETE — 删除资源
curl -X DELETE https://api.example.com/users/1
# HEAD — 仅获取响应头
curl -I https://api.example.com/users/1
# OPTIONS — 获取允许的方法
curl -X OPTIONS https://api.example.com/users -i
2.3 状态码(Status Codes)
状态码是服务器对请求处理结果的数字标识,由三位整数组成。
状态码分类
| 分类 | 范围 | 含义 | 常见示例 |
|---|---|---|---|
| 1xx | 100-199 | 信息性 | 100 Continue, 101 Switching Protocols |
| 2xx | 200-299 | 成功 | 200 OK, 201 Created, 204 No Content |
| 3xx | 300-399 | 重定向 | 301 Moved Permanently, 304 Not Modified |
| 4xx | 400-499 | 客户端错误 | 400 Bad Request, 401, 403, 404 |
| 5xx | 500-599 | 服务器错误 | 500 Internal Server Error, 502, 503 |
最常用的状态码
200 OK — 请求成功
201 Created — 资源已创建
204 No Content — 成功但无响应体
301 Moved Permanently — 永久重定向
302 Found — 临时重定向
304 Not Modified — 未修改(缓存可用)
400 Bad Request — 请求格式错误
401 Unauthorized — 未认证
403 Forbidden — 无权限
404 Not Found — 资源不存在
405 Method Not Allowed — 方法不允许
409 Conflict — 冲突
429 Too Many Requests — 请求过多
500 Internal Server Error — 服务器内部错误
502 Bad Gateway — 网关错误
503 Service Unavailable — 服务不可用
状态码选择决策树
请求成功?
├── 是
│ ├── 创建了新资源? → 201 Created
│ ├── 无响应体返回? → 204 No Content
│ └── 其他 → 200 OK
├── 重定向?
│ ├── 永久移动? → 301
│ └── 临时移动? → 302 / 307
├── 客户端错误?
│ ├── 请求格式错误? → 400
│ ├── 未认证? → 401
│ ├── 无权限? → 403
│ ├── 资源不存在? → 404
│ └── 限流? → 429
└── 服务器错误?
├── 已知错误? → 500
├── 依赖服务故障? → 502
└── 暂时不可用? → 503
2.4 头部字段(Header Fields)
头部字段以 名称: 值 的形式出现,每个字段占一行。
头部字段分类
| 类型 | 描述 | 常见字段 |
|---|---|---|
| 通用头 | 请求和响应都能用 | Cache-Control, Connection, Date |
| 请求头 | 仅出现在请求中 | Host, User-Agent, Accept, Authorization |
| 响应头 | 仅出现在响应中 | Server, Set-Cookie, Content-Type |
| 实体头 | 描述消息体 | Content-Length, Content-Encoding |
关键请求头
Host: www.example.com # 必须,HTTP/1.1 要求
User-Agent: Mozilla/5.0 ... # 客户端标识
Accept: text/html,application/json # 期望的响应格式
Accept-Language: zh-CN,en # 语言偏好
Accept-Encoding: gzip, br # 支持的压缩算法
Authorization: Bearer <token> # 认证凭据
Content-Type: application/json # 请求体格式
Content-Length: 128 # 请求体长度
If-None-Match: "etag-value" # 缓存协商
Connection: keep-alive # 连接管理
关键响应头
Content-Type: application/json; charset=utf-8
Content-Length: 256
Content-Encoding: gzip
Cache-Control: max-age=3600, public
ETag: "abc123"
Set-Cookie: session=xyz; HttpOnly; Secure
Location: /new-resource # 用于重定向
Server: nginx/1.24
Access-Control-Allow-Origin: * # CORS
Strict-Transport-Security: max-age=31536000 # HSTS
2.5 业务场景:用户注册流程
以下是一个用户注册 API 的完整 HTTP 交互过程:
请求
POST /api/v1/users HTTP/1.1
Host: api.myapp.com
Content-Type: application/json
Accept: application/json
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
Content-Length: 82
{
"username": "alice",
"email": "alice@example.com",
"password": "P@ssw0rd123"
}
成功响应(201)
HTTP/1.1 201 Created
Content-Type: application/json
Location: /api/v1/users/123
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
Content-Length: 98
{
"id": 123,
"username": "alice",
"email": "alice@example.com",
"created_at": "2026-05-10T08:00:00Z"
}
错误响应(400)
HTTP/1.1 400 Bad Request
Content-Type: application/json
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
Content-Length: 112
{
"error": {
"code": "VALIDATION_ERROR",
"message": "邮箱格式不正确",
"details": [
{"field": "email", "message": "必须是有效的邮箱地址"}
]
}
}
Node.js 服务端实现
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/api/v1/users') {
let body = '';
req.on('data', chunk => body += chunk);
req.on('end', () => {
try {
const data = JSON.parse(body);
// 简单验证
if (!data.email || !data.email.includes('@')) {
res.writeHead(400, {'Content-Type': 'application/json'});
res.end(JSON.stringify({
error: {
code: 'VALIDATION_ERROR',
message: '邮箱格式不正确'
}
}));
return;
}
// 创建用户
res.writeHead(201, {
'Content-Type': 'application/json',
'Location': '/api/v1/users/123'
});
res.end(JSON.stringify({
id: 123,
username: data.username,
email: data.email,
created_at: new Date().toISOString()
}));
} catch (e) {
res.writeHead(400, {'Content-Type': 'application/json'});
res.end(JSON.stringify({error: {message: '请求体不是有效 JSON'}}));
}
});
} else {
res.writeHead(404, {'Content-Type': 'application/json'});
res.end(JSON.stringify({error: {message: '路由不存在'}}));
}
});
server.listen(3000, () => console.log('Server running on :3000'));
2.6 请求-响应生命周期
客户端 服务器
│ │
│ ─── DNS 解析 ────────────────→│
│ ←── IP 地址 ───────────────── │
│ │
│ ─── TCP 三次握手 ────────────→│
│ ←── 连接建立 ──────────────── │
│ │
│ ─── TLS 握手 (HTTPS) ───────→│
│ ←── 证书 & 密钥交换 ──────── │
│ │
│ ─── HTTP 请求 ──────────────→│
│ │──→ 路由匹配
│ │──→ 权限验证
│ │──→ 业务逻辑
│ │──→ 生成响应
│ ←── HTTP 响应 ─────────────── │
│ │
│ ─── 关闭连接 / 复用 ────────→│
2.7 Content-Type 常见值
Content-Type 指定请求体或响应体的媒体类型:
| Content-Type | 说明 | 示例场景 |
|---|---|---|
text/html | HTML 文档 | 网页响应 |
text/plain | 纯文本 | 简单文本响应 |
application/json | JSON 数据 | RESTful API |
application/xml | XML 数据 | 传统 API |
application/x-www-form-urlencoded | 表单数据 | HTML 表单提交 |
multipart/form-data | 多部分表单 | 文件上传 |
application/octet-stream | 二进制流 | 文件下载 |
image/jpeg | JPEG 图片 | 图片资源 |
# JSON 格式
curl -X POST \
-H "Content-Type: application/json" \
-d '{"name":"Alice"}' \
http://localhost:3000/api
# 表单格式
curl -X POST \
-d "name=Alice&age=25" \
http://localhost:3000/form
# 文件上传
curl -X POST \
-F "file=@/path/to/image.jpg" \
-F "description=my photo" \
http://localhost:3000/upload
⚠️ 注意事项
- Host 头必须存在:HTTP/1.1 强制要求,否则返回 400
- 大小写敏感性:头部字段名不区分大小写,但值可能区分
- CRLF 换行:HTTP 规范要求
\r\n作为行终止符,不是\n - 不要过度依赖 GET 获取敏感数据:GET 的 URL 会被记录在日志、浏览器历史中
- POST 不是万能的:选择正确的方法(PUT 替换、PATCH 更新、DELETE 删除)有助于 API 清晰度
🔗 扩展阅读
- RFC 9110 — HTTP Semantics: Methods
- RFC 9110 — HTTP Semantics: Status Codes
- MDN — HTTP Headers
- HTTP Status Codes Cheat Sheet
下一章:第 3 章:URL 与 URI — URL 语法、编码规则、查询参数、片段标识