HTTP Header是HTTP请求和响应的元数据部分,位于请求/响应行的下方、空行之上。Header以键值对的形式存在,用于传递关于请求或响应的附加信息,而不是实际传输的业务数据。
Header的结构特点:
Header-Name: Header-ValueGET /api/users/123 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
HTTP Body是HTTP消息的实际内容部分,位于Header之后的空行下方。Body承载的是实际的业务数据,如用户提交的信息、服务器返回的资源内容等。
Body的结构特点:
Content-Type Header决定POST /api/orders HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 156
{
"productId": "SKU-12345",
"quantity": 2,
"shippingAddress": {
"street": "123 Main St",
"city": "Shanghai",
"zipCode": "200000"
}
}
| 维度 | Header | Body |
|---|---|---|
| 本质 | 元数据(Metadata) | 业务数据(Payload) |
| 作用 | 描述消息本身 | 传递业务内容 |
| 大小限制 | 通常8KB-16KB | 理论上无限制(受服务器配置约束) |
| 可见性 | 被中间件、代理服务器读取 | 通常只被端点服务器处理 |
| 缓存 | 参与缓存策略决策 | 被缓存的内容本身 |
| 安全处理 | 常被日志记录 | 敏感数据应避免明文记录 |
| 编码 | 必须是ASCII文本 | 可以是任意二进制数据 |
| 结构 | 扁平键值对 | 根据格式可层级嵌套 |
理解Header与Body的关系,需要放在完整的HTTP消息结构中来看:
┌─────────────────────────────────────────────────────────────┐
│ HTTP Request/Response │
├─────────────────────────────────────────────────────────────┤
│ Request Line / Status Line │
│ GET /api/users HTTP/1.1 │
├─────────────────────────────────────────────────────────────┤
│ Headers (Metadata) │
│ Host: api.example.com │
│ Content-Type: application/json │
│ Authorization: Bearer token │
│ ... │
├─────────────────────────────────────────────────────────────┤
│ Empty Line (\r\n) │
├─────────────────────────────────────────────────────────────┤
│ Body (Payload) │
│ {"name": "John", "age": 30} │
└─────────────────────────────────────────────────────────────┘
这种分层设计体现了关注点分离原则:Header关注"如何传输和处理消息",Body关注"传输什么内容"。
认证信息通常放在Header中,因为:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Authorization: Basic dXNlcjpwYXNzd29yZA==
X-API-Key: sk_live_1234567890abcdef
客户端告诉服务器它希望接收什么样的响应:
Accept: application/json # 期望JSON格式
Accept-Language: zh-CN,en-US;q=0.9 # 首选中文,其次是英文
Accept-Encoding: gzip, deflate, br # 支持的压缩算法
描述消息本身的信息:
Content-Type: application/json; charset=utf-8 # Body的格式和编码
Content-Length: 1024 # Body的字节长度
Content-Encoding: gzip # Body的压缩方式
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT # 资源最后修改时间
帮助服务器处理请求的上下文:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Referer: https://www.example.com/previous-page
X-Forwarded-For: 192.168.1.1, 10.0.0.1 # 经过代理后的原始IP
X-Request-ID: 550e8400-e29b-41d4-a716-... # 请求追踪ID
控制缓存策略:
Cache-Control: no-cache, no-store, must-revalidate
ETag: "33a64df5" # 资源版本标识
If-None-Match: "33a64df5" # 条件请求
增强安全性的Header:
X-Content-Type-Options: nosniff # 禁止MIME嗅探
X-Frame-Options: DENY # 禁止嵌入iframe
Strict-Transport-Security: max-age=31536000 # 强制HTTPS
核心的业务对象信息必须放在Body中:
{
"orderId": "ORD-2025-001",
"customer": {
"id": "CUST-12345",
"name": "张三"
},
"items": [
{"productId": "SKU-001", "quantity": 2, "price": 99.99}
],
"totalAmount": 199.98
}
层级嵌套的数据结构适合放在Body:
{
"company": {
"name": "Example Corp",
"departments": [
{
"name": "Engineering",
"teams": [
{"name": "Backend", "members": 15},
{"name": "Frontend", "members": 10}
]
}
]
}
}
文件上传、图片等二进制内容:
POST /api/uploads HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="document.pdf"
Content-Type: application/pdf
[二进制PDF数据]
------WebKitFormBoundary--
批量创建、更新、删除的数据:
{
"operations": [
{"action": "create", "data": {...}},
{"action": "update", "data": {...}},
{"action": "delete", "data": {...}}
]
}
开始
│
├─ 这是描述消息如何被处理的信息? ──┬─是──► 放入Header
│ │
│ └─否─┐
│ │
└─ 这是认证/授权信息? ──────────────┬─是──► 放入Header
│
└─否─┐
│
└─ 这是内容协商信息? ──────────────┬─是──► 放入Header
│
└─否─┐
│
└─ 这是业务数据/实体信息? ─────────┬─是──► 放入Body
│
└─否─┐
│
└─ 这是复杂结构化数据? ────────────┬─是──► 放入Body
│
└─否──► 根据具体情况判断
错误做法:
GET /api/orders HTTP/1.1
X-Order-Id: ORD-12345
X-Customer-Id: CUST-67890
X-Start-Date: 2025-01-01
正确做法:
GET /api/orders?orderId=ORD-12345&customerId=CUST-67890&startDate=2025-01-01 HTTP/1.1
原则: 查询参数属于URL的一部分,不要滥用Header。
错误做法:
POST /api/orders HTTP/1.1
X-Order-Data: {"items":[{"id":"1","name":"Product A","description":"Very long description..."}]}
正确做法:
POST /api/orders HTTP/1.1
Content-Type: application/json
{"items":[{"id":"1","name":"Product A","description":"Very long description..."}]}
原则: Header有大小限制(通常8-16KB),大数据量应放Body。
错误做法:
GET /api/users?password=secret123 HTTP/1.1
或
POST /api/login HTTP/1.1
X-Password: secret123
正确做法:
POST /api/login HTTP/1.1
Content-Type: application/json
{"username":"john","password":"secret123"}
原则: URL会被记录在服务器日志、浏览器历史中;敏感数据应加密后放在Body中传输。
RESTful API强调资源的表述和状态转移,Header在这一架构中扮演重要角色:
客户端通过Header声明可接受的资源表述格式:
GET /api/users/123 HTTP/1.1
Accept: application/json
Accept: application/xml
Accept: application/hal+json
服务器根据Accept Header返回对应格式,并通过Content-Type告知实际返回的格式:
HTTP/1.1 200 OK
Content-Type: application/json
{"id": 123, "name": "John Doe"}
RESTful API通过状态码和Header共同表达结果:
HTTP/1.1 201 Created
Location: /api/users/123 # 新资源的URL
Content-Type: application/json
{"id": 123, "name": "John Doe"}
HTTP/1.1 204 No Content
ETag: "abc123" # 资源版本
HTTP/1.1 200 OK
Link: </api/users?page=2>; rel="next", </api/users?page=10>; rel="last"
# 客户端获取资源时记录版本
GET /api/users/123 HTTP/1.1
HTTP/1.1 200 OK
ETag: "33a64df5"
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT
# 更新时携带版本信息,防止冲突
PUT /api/users/123 HTTP/1.1
If-Match: "33a64df5"
If-Unmodified-Since: Wed, 21 Oct 2025 07:28:00 GMT
HTTP/1.1 412 Precondition Failed # 如果资源已被修改
HTTP/1.1 200 OK
X-Total-Count: 1000
X-Page-Size: 20
X-Current-Page: 1
X-Total-Pages: 50
Link: </api/users?page=2>; rel="next"
当需要自定义Header时,应遵循以下规范:
X- 前缀表示自定义Header(虽然RFC 6648已废弃此约定,但实践中仍广泛使用)X-Company-推荐格式:
X-Request-ID: uuid
X-Client-Version: 1.2.3
X-API-Version: v2
X-Correlation-ID: abc123
X-Custom-* 命名| 方案 | 示例 | 优点 | 缺点 |
|---|---|---|---|
| URL路径 | /v2/users |
直观,易于缓存 | URL变化,不符合REST原则 |
| Header | API-Version: v2 |
URL稳定 | 需要文档说明 |
| Accept Header | Accept: application/vnd.api.v2+json |
符合HTTP语义 | 复杂,学习成本高 |
| 自定义Header | X-API-Version: v2 |
简单清晰 | 非标准做法 |
GET /api/users HTTP/1.1
X-API-Version: 2.0
Accept: application/json
或
GET /api/users HTTP/1.1
Accept: application/vnd.company.api.v2+json
作用: 指示Body的媒体类型和编码
常见值:
application/json - JSON数据application/xml - XML数据application/x-www-form-urlencoded - 表单数据multipart/form-data - 多部分表单(含文件上传)text/plain - 纯文本text/html - HTML文档application/octet-stream - 二进制流带参数的用法:
Content-Type: application/json; charset=utf-8
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
作用: 客户端声明可接受的响应格式
质量因子(q值):
Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
表示:
text/htmlapplication/xhtml+xmlapplication/xml(权重0.9)*/*(权重0.8)Accept-Charset: utf-8, iso-8859-1;q=0.5
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Bearer Token(JWT等):
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Basic Auth:
Authorization: Basic base64(username:password)
# 示例:Authorization: Basic YWRtaW46c2VjcmV0
Digest Auth:
Authorization: Digest username="admin", realm="", nonce="...", uri="/api", response="..."
服务器要求客户端认证:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api", error="invalid_token", error_description="Token expired"
用于代理服务器认证,格式与Authorization相同。
作用: 分布式系统中追踪请求链路
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
X-Correlation-ID: abc-123-def-456
最佳实践:
作用: 获取客户端真实IP(经过反向代理)
X-Forwarded-For: client, proxy1, proxy2
# 示例:X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178
注意: 第一个IP是原始客户端IP,后面的都是代理IP。
X-Forwarded-Proto: https # 原始协议
X-Forwarded-Host: www.example.com # 原始Host
X-Forwarded-Port: 443 # 原始端口
请求指令:
Cache-Control: no-cache # 强制重新验证
Cache-Control: no-store # 不存储任何版本
Cache-Control: max-age=3600 # 最大有效时间(秒)
Cache-Control: only-if-cached # 只接受缓存副本
响应指令:
Cache-Control: public # 可被任何缓存存储
Cache-Control: private # 只被浏览器缓存
Cache-Control: no-cache # 必须先验证
Cache-Control: no-store # 不缓存
Cache-Control: max-age=3600 # 缓存1小时
Cache-Control: s-maxage=3600 # CDN共享缓存时间
Cache-Control: must-revalidate # 过期后必须重新验证
Cache-Control: immutable # 内容永不变(用于带hash的静态资源)
组合使用:
Cache-Control: public, max-age=31536000, immutable
ETag生成:
HTTP/1.1 200 OK
ETag: "686897696a7c876b7e" # 强验证
ETag: W/"686897696a7c876b7e" # 弱验证(W/前缀)
条件请求:
GET /api/users/123 HTTP/1.1
If-None-Match: "686897696a7c876b7e"
HTTP/1.1 304 Not Modified # 资源未变化,返回空Body
HTTP/1.1 200 OK
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT
GET /api/users/123 HTTP/1.1
If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT
HTTP/1.1 304 Not Modified
作用: 防止XSS攻击,限制资源加载来源
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' cdn.example.com; img-src *; style-src 'self' 'unsafe-inline'
作用: 强制浏览器使用HTTPS
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
作用: 禁止浏览器MIME嗅探
X-Content-Type-Options: nosniff
作用: 防止点击劫持
X-Frame-Options: DENY # 完全禁止嵌入
X-Frame-Options: SAMEORIGIN # 只允许同源嵌入
X-Frame-Options: ALLOW-FROM https://example.com
作用: 启用浏览器XSS过滤器(现代浏览器已弃用,推荐用CSP)
X-XSS-Protection: 1; mode=block
简单请求:
GET /api/data HTTP/1.1
Origin: https://example.com
预检请求(OPTIONS):
OPTIONS /api/data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header
Access-Control-Allow-Origin: https://example.com # 或 *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true # 允许携带Cookie
Access-Control-Max-Age: 86400 # 预检结果缓存时间
Access-Control-Expose-Headers: X-Total-Count # 允许客户端读取的Header
适用场景:
优点:
缺点:
{
"user": {
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"roles": ["admin", "editor"],
"metadata": {
"createdAt": "2025-01-15T08:30:00Z",
"lastLogin": "2025-03-22T10:15:00Z"
}
}
}
适用场景:
优点:
缺点:
<?xml version="1.0" encoding="UTF-8"?>
<user>
<id>123</id>
<name>John Doe</name>
<email>john@example.com</email>
<roles>
<role>admin</role>
<role>editor</role>
</roles>
</user>
适用场景:
name=John+Doe&email=john%40example.com&age=30
适用场景:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="name"
John Doe
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="avatar.jpg"
Content-Type: image/jpeg
[二进制图片数据]
------WebKitFormBoundary--
适用场景:
优点:
缺点:
键命名:
// ✅ 推荐:camelCase(JavaScript风格)
{
"firstName": "John",
"lastName": "Doe",
"createdAt": "2025-01-01"
}
// ✅ 可接受:snake_case(Python/Ruby风格)
{
"first_name": "John",
"last_name": "Doe",
"created_at": "2025-01-01"
}
// ❌ 避免:kebab-case(JSON键中不常见)
{
"first-name": "John"
}
团队内部应统一风格。
ISO 8601格式(推荐):
{
"createdAt": "2025-03-22T13:30:00Z", # UTC时间
"createdAt": "2025-03-22T13:30:00+08:00", # 带时区
"dateOnly": "2025-03-22" # 仅日期
}
Unix时间戳(备选):
{
"createdAt": 1711113000 # 秒级
"createdAt": 1711113000000 # 毫秒级(带说明)
}
{
// ✅ 显式null
"middleName": null,
// ✅ 空数组
"tags": [],
// ✅ 空对象
"metadata": {},
// ❌ 避免:缺少字段(除非真的可选)
"middleName": undefined // JSON不支持undefined
}
推荐: 最多3-4层嵌套
// ✅ 良好的层次结构
{
"order": {
"id": "ORD-001",
"customer": {
"id": "CUST-001",
"address": {
"city": "Shanghai"
}
}
}
}
// ❌ 过深的嵌套,难以维护
{
"a": {
"b": {
"c": {
"d": {
"e": {
"f": "too deep"
}
}
}
}
}
}
// ✅ 推荐:包装对象,便于扩展
{
"data": [
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"}
],
"pagination": {
"page": 1,
"pageSize": 20,
"total": 100,
"totalPages": 5
}
}
// ❌ 避免:直接返回数组
[
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"}
]
标准错误格式:
{
"type": "https://api.example.com/errors/insufficient-funds",
"title": "Insufficient Funds",
"status": 402,
"detail": "Your current balance is 30, but the operation costs 50.",
"instance": "/transactions/550e8400-e29b-41d4-a716-446655440000",
"balance": 30,
"accounts": ["/accounts/12345", "/accounts/67890"]
}
字段说明:
type:错误类型的URI标识title:简短可读的错误描述status:HTTP状态码detail:详细的人类可读说明instance:具体错误实例的URI{
"error": {
"code": "INVALID_PAYMENT_METHOD",
"message": "The provided payment method has expired.",
"details": [
{
"field": "paymentMethod.expiryDate",
"issue": "EXPIRED",
"description": "Card expired on 2025-01-01"
}
]
}
}
POST /api/users
Content-Type: application/json
{
"username": "johndoe",
"email": "john@example.com",
"password": "securePassword123",
"profile": {
"firstName": "John",
"lastName": "Doe",
"dateOfBirth": "1990-05-15"
}
}
POST /api/users/batch
Content-Type: application/json
{
"operations": [
{
"action": "create",
"data": {"username": "user1", "email": "user1@example.com"}
},
{
"action": "update",
"id": "user-2",
"data": {"email": "newemail@example.com"}
},
{
"action": "delete",
"id": "user-3"
}
]
}
JSON Patch格式:
PATCH /api/users/123
Content-Type: application/json-patch+json
[
{"op": "replace", "path": "/email", "value": "new@example.com"},
{"op": "add", "path": "/tags/-", "value": "premium"},
{"op": "remove", "path": "/oldField"}
]
JSON Merge Patch格式:
PATCH /api/users/123
Content-Type: application/merge-patch+json
{
"email": "new@example.com",
"tags": ["premium"],
"oldField": null
}
简化PATCH(最常用):
PATCH /api/users/123
Content-Type: application/json
{
"email": "new@example.com",
"tags": ["premium"]
}
POST /api/v2/payments HTTP/1.1
Host: api.payment-gateway.com
Content-Type: application/json
Content-Length: 567
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
X-Request-ID: pay-req-550e8400-e29b-41d4-a716-446655440000
X-Merchant-ID: MERCHANT-123456
X-Timestamp: 2025-03-22T13:30:00Z
X-Signature: sha256=8f7d88d7a87f8d8a7f8d7a8f...
Idempotency-Key: idem-abc123def456
{
"amount": {
"value": "99.99",
"currency": "CNY"
},
"order": {
"orderId": "ORDER-2025-001",
"description": "Premium Subscription - Monthly",
"items": [
{
"sku": "SUB-PREMIUM-MONTHLY",
"name": "Premium Subscription",
"quantity": 1,
"unitPrice": "99.99"
}
]
},
"payer": {
"payerId": "USER-123456",
"paymentMethod": {
"type": "credit_card",
"card": {
"number": "4111111111111111",
"expiryMonth": "12",
"expiryYear": "2027",
"cvv": "123",
"holderName": "John Doe"
}
}
},
"notifyUrl": "https://merchant.example.com/webhooks/payment",
"returnUrl": "https://merchant.example.com/payment/success",
"riskData": {
"ipAddress": "203.0.113.42",
"deviceFingerprint": "fp-abc123",
"geoLocation": {
"country": "CN",
"city": "Shanghai"
}
}
}
Header说明:
| Header | 说明 | 作用 |
|---|---|---|
Authorization |
Bearer Token | 商户身份认证 |
X-Request-ID |
唯一请求ID | 追踪和日志记录 |
X-Merchant-ID |
商户标识 | 路由到正确的商户账户 |
X-Timestamp |
请求时间戳 | 防重放攻击、请求时效验证 |
X-Signature |
请求签名 | 确保请求完整性 |
Idempotency-Key |
幂等键 | 防止重复处理 |
HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 892
X-Request-ID: pay-req-550e8400-e29b-41d4-a716-446655440000
X-Transaction-ID: TXN-9876543210
X-Processing-Time: 245
Location: /api/v2/payments/PAY-abc123def456
{
"paymentId": "PAY-abc123def456",
"transactionId": "TXN-9876543210",
"status": "PROCESSING",
"amount": {
"value": "99.99",
"currency": "CNY"
},
"merchant": {
"merchantId": "MERCHANT-123456",
"orderId": "ORDER-2025-001"
},
"payer": {
"payerId": "USER-123456",
"maskedCardNumber": "411111******1111"
},
"timeline": {
"createdAt": "2025-03-22T13:30:00.123Z",
"expiresAt": "2025-03-22T13:45:00Z"
},
"nextAction": {
"type": "3DS_AUTHENTICATION",
"redirectUrl": "https://3ds.bank.com/authenticate?token=xyz",
"fallbackUrl": "https://api.payment-gateway.com/3ds/callback"
},
"metadata": {
"gatewayReference": "GW-ref-12345",
"riskScore": 25,
"riskLevel": "LOW"
}
}
GET /api/v2/payments/PAY-abc123def456 HTTP/1.1
Host: api.payment-gateway.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
X-Request-ID: query-req-550e8400-e29b-41d4-a716-446655440000
X-Merchant-ID: MERCHANT-123456
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-ID: query-req-550e8400-e29b-41d4-a716-446655440000
Cache-Control: private, max-age=5
{
"paymentId": "PAY-abc123def456",
"status": "COMPLETED",
"amount": {
"value": "99.99",
"currency": "CNY"
},
"timeline": {
"createdAt": "2025-03-22T13:30:00.123Z",
"authorizedAt": "2025-03-22T13:30:05.456Z",
"capturedAt": "2025-03-22T13:30:10.789Z",
"completedAt": "2025-03-22T13:30:10.789Z"
},
"transactions": [
{
"transactionId": "TXN-9876543210",
"type": "AUTHORIZATION",
"amount": "99.99",
"status": "SUCCESS",
"processorResponse": {
"code": "00",
"message": "Approved"
}
},
{
"transactionId": "TXN-9876543211",
"type": "CAPTURE",
"amount": "99.99",
"status": "SUCCESS"
}
]
}
POST /webhooks/payment HTTP/1.1
Host: merchant.example.com
Content-Type: application/json
X-Webhook-ID: wh-550e8400-e29b-41d4-a716-446655440000
X-Event-Type: payment.completed
X-Signature: sha256=7d8f9a8b7c6d5e4f3a2b1c0d9e8f7a6b...
User-Agent: PaymentGateway-Webhook/2.0
{
"eventId": "EVT-2025-001",
"eventType": "payment.completed",
"timestamp": "2025-03-22T13:30:10.789Z",
"data": {
"paymentId": "PAY-abc123def456",
"merchantId": "MERCHANT-123456",
"orderId": "ORDER-2025-001",
"status": "COMPLETED",
"amount": {
"value": "99.99",
"currency": "CNY"
},
"completedAt": "2025-03-22T13:30:10.789Z"
}
}
POST /api/v2/payments/PAY-abc123def456/refunds HTTP/1.1
Host: api.payment-gateway.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
X-Request-ID: refund-req-550e8400-e29b-41d4-a716-446655440000
Idempotency-Key: idem-refund-001
{
"amount": {
"value": "99.99",
"currency": "CNY"
},
"reason": "Customer request",
"referenceId": "REFUND-2025-001",
"notifyUrl": "https://merchant.example.com/webhooks/refund"
}
HTTP/1.1 202 Accepted
Content-Type: application/json
X-Request-ID: refund-req-550e8400-e29b-41d4-a716-446655440000
Location: /api/v2/refunds/REF-xyz789abc
{
"refundId": "REF-xyz789abc",
"paymentId": "PAY-abc123def456",
"status": "PENDING",
"amount": {
"value": "99.99",
"currency": "CNY"
},
"reason": "Customer request",
"referenceId": "REFUND-2025-001",
"estimatedCompletion": "2025-03-22T15:30:00Z"
}
POST /api/v2/payments/batch-query HTTP/1.1
Host: api.payment-gateway.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
X-Request-ID: batch-query-550e8400-e29b-41d4-a716-446655440000
{
"paymentIds": [
"PAY-abc123def456",
"PAY-ghi789jkl012",
"PAY-mno345pqr678"
]
}
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-ID: batch-query-550e8400-e29b-41d4-a716-446655440000
{
"results": [
{
"paymentId": "PAY-abc123def456",
"status": "COMPLETED",
"amount": {"value": "99.99", "currency": "CNY"}
},
{
"paymentId": "PAY-ghi789jkl012",
"status": "FAILED",
"error": {"code": "INSUFFICIENT_FUNDS", "message": "..."}
},
{
"paymentId": "PAY-mno345pqr678",
"status": "NOT_FOUND"
}
],
"summary": {
"total": 3,
"succeeded": 1,
"failed": 1,
"notFound": 1
}
}
基于以上案例,总结支付系统的Header设计原则:
Authorization用于身份验证X-Signature确保请求完整性X-Timestamp防止重放攻击Idempotency-Key保证操作幂等X-Request-ID贯穿整个调用链X-Transaction-ID标识具体交易X-Merchant-ID用于路由和权限X-Processing-Time记录服务器处理耗时Cache-Control避免重复查询❌ 错误示例
POST /api/orders HTTP/1.1
X-Product-Id: SKU-12345
X-Quantity: 2
X-Customer-Id: CUST-67890
问题:
正确做法:
✅ 正确示例
POST /api/orders HTTP/1.1
Content-Type: application/json
{
"productId": "SKU-12345",
"quantity": 2,
"customerId": "CUST-67890"
}
❌ 错误示例
content-type: application/json # 小写
x_api_key: secret123 # 下划线
X-custom-header: value # 不规范命名
正确做法:
✅ 正确示例
Content-Type: application/json # 首字母大写,连字符分隔
X-API-Key: secret123 # 连字符分隔
X-Custom-Header: value # 规范命名
❌ 错误示例
GET /api/payments?creditCard=4111111111111111 HTTP/1.1
❌ 错误示例
POST /api/login HTTP/1.1
X-Password: mySecretPassword
问题:
正确做法:
✅ 正确示例
POST /api/login HTTP/1.1
Content-Type: application/json
{
"username": "john",
"password": "mySecretPassword"
}
❌ 错误示例
POST /api/users HTTP/1.1
Content-Type: application/json
name=John&age=30 # 实际是form格式
正确做法:
✅ 正确示例
POST /api/users HTTP/1.1
Content-Type: application/x-www-form-urlencoded
name=John&age=30
或
✅ 正确示例
POST /api/users HTTP/1.1
Content-Type: application/json
{"name": "John", "age": 30}
❌ 错误示例
{
name: "John", // 缺少引号
age: 30, // 末尾多余逗号(某些解析器不接受)
}
正确做法:
✅ 正确示例
{
"name": "John",
"age": 30
}
❌ 错误示例
{
"createdAt": "2025-03-22 13:30:00", // 非标准格式
"updatedAt": 1711113000, // Unix时间戳
"deletedAt": "03/22/2025" // 另一种格式
}
正确做法:
✅ 正确示例
{
"createdAt": "2025-03-22T13:30:00Z",
"updatedAt": "2025-03-22T13:45:00Z",
"deletedAt": "2025-03-23T10:00:00Z"
}
❌ 错误示例
[
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"}
]
问题:
正确做法:
✅ 正确示例
{
"data": [
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"}
],
"pagination": {
"page": 1,
"pageSize": 20,
"total": 100
}
}
❌ 错误示例 - 错误1
{
"error": "Invalid input"
}
❌ 错误示例 - 错误2
{
"message": "User not found",
"code": 404
}
❌ 错误示例 - 错误3
{
"errors": [
{"field": "email", "message": "Invalid email"}
]
}
正确做法: 统一错误格式
✅ 正确示例
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Input validation failed",
"details": [
{"field": "email", "message": "Invalid email format"}
]
}
}
X-前缀null或空数组,避免undefinedCache-Control、ETag等gzip、br压缩# 查看完整的请求和响应
# GET请求
curl -v https://api.example.com/users \
-H "Accept: application/json" \
-H "Authorization: Bearer token"
# POST JSON
curl -v https://api.example.com/users \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer token" \
-d '{"name": "John", "email": "john@example.com"}'
# 保存响应到文件
curl https://api.example.com/users -o response.json
Header是元数据,Body是业务数据
数据归属决策
RESTful API设计
常见Header熟练掌握
Body设计规范
安全性不可忽视
| 数据类型 | 推荐位置 | 示例 |
|---|---|---|
| 认证Token | Header | Authorization: Bearer xxx |
| API Key | Header | X-API-Key: xxx |
| 请求追踪ID | Header | X-Request-ID: uuid |
| 客户端信息 | Header | User-Agent、X-Forwarded-For |
| 内容格式声明 | Header | Content-Type、Accept |
| 业务实体ID | URL Path | /api/users/123 |
| 过滤条件 | URL Query | ?status=active&page=1 |
| 业务对象数据 | Body | {"name": "John", ...} |
| 批量数据 | Body | {"items": [...]} |
| 文件内容 | Body (multipart) | Content-Type: multipart/form-data |
官方规范
推荐书籍
在线资源
本文档旨在帮助开发者理解HTTP Header与Body的设计原则,规范API开发实践。如有问题或建议,欢迎反馈。
文档版本: 2.0
最后更新: 2025-03-22
作者: Hugo Knowledge Base