RESTful API 请求和响应

请求头与响应头的分工、状态码的正确用法、统一响应体结构。

Beginner
Key Points请求头描述「我想要什么」,响应头描述「你拿到了什么」,状态码描述「结果如何」;业务错误用 4xx,不要一律 200。

请求头

Text
POST /api/users HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
Accept: application/json
Idempotency-Key: 3f2a9c10-8b7e-4a1d-9c2f-1e5b7d0a6c33

{"name": "Alice", "email": "alice@example.com"}
  • Authorization — 身份凭证,别放 URL 里(会进日志)
  • Content-Type — 我发的是什么格式
  • Accept — 我想收什么格式
  • If-None-Match — 缓存校验,配合 ETag 使用

状态码

CodeWhen
200 OKRead or update succeeded with a body
201 CreatedA resource was created; include Location
204 No ContentSucceeded, nothing to return (DELETE/PUT)
400 Bad RequestMalformed syntax or missing field
401 UnauthorizedMissing or invalid credentials
403 ForbiddenAuthenticated but not allowed
404 Not FoundNo such resource (or hidden from you)
409 ConflictState conflict, e.g. duplicate email
422 Unprocessable EntitySyntax fine, semantics invalid
429 Too Many RequestsRate limited; send Retry-After
500 / 503Server fault / temporarily unavailable
The classic mistake is returning 200 for everything and putting the error in the body: monitoring, gateways, caches and SDKs all break. The status code is for machines, the error body for humans — provide both.

统一响应体

Return the object itself for a single resource — no {code, data} wrapper. Collections return an object carrying pagination. Error bodies keep a fixed shape so clients can handle them uniformly.

JSON
// 单个资源
{"id": 42, "name": "Alice", "email": "alice@example.com"}

// 列表
{"items": [{"id": 42, "name": "Alice"}], "total": 137, "page": 1, "size": 20}

// 错误
{"error": {"code": "EMAIL_TAKEN", "message": "email already registered",
           "details": [{"field": "email", "issue": "duplicate"}]}}

内容协商

Text
GET /users/42
Accept: application/json          → 200, Content-Type: application/json
Accept: text/csv                  → 200, Content-Type: text/csv
Accept: application/xml           → 406 Not Acceptable(不支持)

几个完整例子

Text
# 创建成功
HTTP/1.1 201 Created
Location: /api/users/42
{"id": 42, "name": "Alice"}

# 资源不存在
HTTP/1.1 404 Not Found
{"error": {"code": "NOT_FOUND", "message": "user 42 does not exist"}}

# 参数不合法
HTTP/1.1 422 Unprocessable Entity
{"error": {"code": "VALIDATION_FAILED", "message": "invalid input",
           "details": [{"field": "age", "issue": "must be >= 0"}]}}

Friends & Partners