3. HTTP 基础回顾:请求方法、状态码、请求头与响应头、RESTful API 设计原则
在深入 Go 语言的 API 契约校验之前,必须牢固掌握 HTTP 协议的核心要素。本章将系统回顾 HTTP 请求方法、状态码、头部字段以及 RESTful API 的设计原则,为后续的契约定义与校验打下坚实基础。
3.1 HTTP 请求方法
HTTP 请求方法(也称为 HTTP 动词)定义了客户端对服务器资源期望执行的操作。在 RESTful API 设计中,常用的方法有五种:
| 方法 | 语义 | 幂等性 | 安全性 | 请求体 |
|---|---|---|---|---|
| GET | 获取资源 | 是 | 是 | 无 |
| POST | 创建资源 | 否 | 否 | 有 |
| PUT | 整体更新/替换资源 | 是 | 否 | 有 |
| PATCH | 部分更新资源 | 否 | 否 | 有 |
| DELETE | 删除资源 | 是 | 否 | 通常无 |
幂等性要点: 幂等方法意味着多次执行与单次执行对服务器资源产生的副作用相同。例如,多次
DELETE /users/123 的结果都是资源被删除(或返回 404),但多次 POST /users 会创建多个用户,因此不幂等。
3.2 HTTP 状态码
状态码是服务器对请求结果的标准化响应。按类别分为五大类,API 设计中常用的状态码如下:
| 类别 | 范围 | 常用状态码 | 含义 |
|---|---|---|---|
| 1xx | 100-199 | 100 Continue | 信息性响应,客户端应继续发送请求体 |
| 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 Unauthorized 403 Forbidden 404 Not Found 409 Conflict 422 Unprocessable Entity |
客户端错误 未认证 无权限 资源不存在 资源冲突(如重复创建) 请求体校验失败 |
| 5xx | 500-599 | 500 Internal Server Error 503 Service Unavailable |
服务器内部错误 服务暂时不可用 |
契约校验关注点: 在定义 API 契约时,必须明确每个端点可能返回的所有状态码及其对应的响应结构。例如,
POST /orders 成功应返回 201 Created,而校验失败应返回 422 Unprocessable Entity 并附带错误详情。
3.3 请求头与响应头
HTTP 头部字段用于传递元数据,是契约校验中不可忽视的部分。以下是与 API 契约密切相关的常用头部:
3.3.1 常见请求头
- Content-Type:请求体的媒体类型,如
application/json、application/xml。 - Accept:客户端期望的响应媒体类型。
- Authorization:认证凭证,如
Bearer <token>。 - X-Request-ID:用于链路追踪的请求唯一标识。
3.3.2 常见响应头
- Content-Type:响应体的媒体类型。
- Location:创建资源后的 URI,通常与
201 Created配合使用。 - Cache-Control:缓存策略指令。
- X-RateLimit-Remaining:API 限流剩余次数。
契约校验实践: 在 Go 中,使用
net/http 标准库时,可通过 r.Header.Get("Content-Type") 获取请求头,通过 w.Header().Set("X-Request-ID", uuid) 设置响应头。契约测试框架(如 pact-go)允许精确匹配头部字段。
3.4 RESTful API 设计原则
REST(Representational State Transfer)是一种架构风格,其核心原则指导着现代 API 的设计。以下是六大关键原则:
- 资源导向:一切皆资源,使用名词而非动词命名端点,如
/users而非/getUsers。 - 无状态:每个请求包含所有必要信息,服务器不保存客户端上下文。
- 统一接口:使用标准 HTTP 方法(GET/POST/PUT/PATCH/DELETE)操作资源。
- 可寻址性:每个资源有唯一的 URI,如
/users/123。 - 表现层状态:客户端通过请求头
Accept和Content-Type协商资源的表现形式(JSON/XML)。 - 超媒体驱动(HATEOAS):响应中包含相关资源的链接,引导客户端发现下一步操作。
以下 SVG 图展示了 RESTful API 的核心交互流程:
3.5 RESTful API 端点设计示例
以下是一个典型的用户管理 API 端点设计,展示了如何将上述原则落地:
| 方法 | 端点 | 描述 | 成功状态码 | 请求体示例 |
|---|---|---|---|---|
| GET | /users |
获取用户列表 | 200 OK | 无 |
| GET | /users/{id} |
获取单个用户 | 200 OK | 无 |
| POST | /users |
创建新用户 | 201 Created | |
| PUT | /users/{id} |
整体更新用户 | 200 OK | |
| PATCH | /users/{id} |
部分更新用户 | 200 OK | |
| DELETE | /users/{id} |
删除用户 | 204 No Content | 无 |
命名规范: 端点使用复数名词(
/users 而非 /user),路径参数使用小写字母和连字符(/order-items 而非 /orderItems)。查询参数用于过滤、排序和分页,如 /users?page=1&size=20&sort=name。
3.6 契约校验中的 HTTP 要素
在 Go 的契约测试中,以下 HTTP 要素是校验的核心对象:
- 请求方法 + 路径:构成端点的唯一标识。
- 请求头:特别是
Content-Type和Authorization。 - 请求体:JSON Schema 或 Protobuf 定义的结构。
- 响应状态码:每个端点必须明确所有可能的返回码。
- 响应头:如
Location、Content-Type。 - 响应体:与请求体对应的结构定义。
以下 SVG 图展示了契约校验如何覆盖 HTTP 请求-响应的完整生命周期:
Go 实战提示: 在 Go 中,可以使用
net/http/httptest 包模拟 HTTP 请求与响应,结合 encoding/json 进行序列化/反序列化。契约测试框架(如 pact-go 或 go-restful)会自动生成请求-响应匹配规则,开发者只需定义契约文件即可。