3. 接口校验基础:HTTP 协议回顾、请求方法、状态码与报文结构

接口校验是压测用例的“裁判员”。没有校验,压测只是空转。而校验的根基,是 HTTP 协议。本章从后端测试视角,快速回顾 HTTP 的核心要素:请求方法、状态码、请求头与响应体结构。这些知识将直接用于后续的 Testing 断言与压测指标设计。

3.1 HTTP 协议核心要素

HTTP(HyperText Transfer Protocol)是客户端与服务端之间无状态的请求-响应协议。一次完整的 HTTP 交互包含以下要素:

  • 请求行:方法 + URI + 协议版本
  • 请求头:元数据,如 Content-Type、Authorization
  • 请求体:POST/PUT 携带的数据
  • 状态行:协议版本 + 状态码 + 原因短语
  • 响应头:服务端返回的元数据
  • 响应体:服务端返回的数据
压测视角: 压测工具(如 k6、wrk、Locust)本质上是构造 HTTP 请求并收集响应。理解报文结构,才能精准设置请求参数和断言条件。
HTTP 请求-响应交互流程 客户端 (压测工具 / 浏览器) 服务端 (API 网关 / 应用) HTTP 请求 GET /api/users HTTP/1.1 HTTP 响应 200 OK / 404 Not Found 核心校验点 状态码 ∈ {200, 201, 204, 400, 401, 403, 404, 500} | 响应体 JSON 结构 | 响应时间

3.2 请求方法:CRUD 的 HTTP 映射

RESTful 接口中,请求方法对应资源的操作类型。压测用例必须为每个接口选择正确的方法,否则校验必然失败。

方法 语义 幂等 请求体 典型状态码 压测场景
GET 查询资源 是 无 200 读接口压测,关注响应时间与数据正确性
POST 创建资源 否 有 201 / 400 写接口压测,关注重复提交与数据一致性
PUT 全量更新 是 有 200 / 204 更新接口压测,关注幂等性校验
DELETE 删除资源 是 无 204 / 404 删除接口压测,关注资源不存在时的处理
PATCH 部分更新 否 有 200 / 400 部分更新压测,关注字段级校验
幂等性陷阱: 压测中重复发送 POST 请求可能产生重复数据。测试用例应设计幂等键(Idempotency-Key)或使用 PUT 替代 POST 来避免脏数据。

3.3 状态码:接口健康的“红绿灯”

状态码是服务端对请求的“判决”。压测校验的第一步就是断言状态码是否符合预期。以下是后端测试中最常遇到的分类:

  • 2xx 成功
    • 200 OK:GET、PUT、PATCH 成功
    • 201 Created:POST 创建成功
    • 204 No Content:DELETE 成功,无响应体
  • 3xx 重定向
    • 301 Moved Permanently:资源永久迁移
    • 302 Found:临时重定向
    • 304 Not Modified:缓存未过期
  • 4xx 客户端错误
    • 400 Bad Request:参数校验失败
    • 401 Unauthorized:未认证
    • 403 Forbidden:无权限
    • 404 Not Found:资源不存在
    • 429 Too Many Requests:限流触发
  • 5xx 服务端错误
    • 500 Internal Server Error:服务内部异常
    • 502 Bad Gateway:网关/代理错误
    • 503 Service Unavailable:服务过载或维护
    • 504 Gateway Timeout:上游超时
压测校验红线: 压测期间,5xx 状态码占比应严格为 0%。如果出现 429,说明限流策略生效,需评估限流阈值是否合理。4xx 状态码需区分是测试数据问题还是接口逻辑缺陷。

3.4 请求头与响应体结构

接口校验不仅看状态码,还要验证请求头与响应体的内容。以下是后端测试中最关键的字段:

3.4.1 常见请求头

请求头 说明 压测校验点
Content-Type 请求体格式,如 application/json 必须与服务端期望一致
Authorization 认证令牌,如 Bearer <token> 压测前需获取有效 token,关注过期时间
Accept 客户端期望的响应格式 确保服务端返回正确的 Content-Type
X-Request-Id 请求追踪 ID 用于链路追踪,压测中应生成唯一值
Idempotency-Key 幂等键,防止重复提交 POST 压测时建议携带

3.4.2 响应体结构校验

响应体通常是 JSON 格式。压测用例需要校验以下维度:

  • 字段存在性:关键字段是否返回(如 id、status)
  • 字段类型:string、number、boolean、array、object
  • 字段值范围:数值是否在合理区间,字符串是否为空
  • 嵌套结构:深层 JSON 对象的层级是否正确
  • 数组长度:分页接口的 items 数组长度是否与 pageSize 一致
// 示例:用户列表接口响应体校验
{
  "code": 200,                // 业务状态码
  "message": "success",
  "data": {
    "total": 100,             // 总数,必须为 number
    "page": 1,                // 当前页,必须为 number
    "pageSize": 10,           // 每页条数,必须为 number
    "items": [                // 数组,长度 ≤ pageSize
      {
        "id": "u_001",        // 字符串,非空
        "name": "张三",        // 字符串,非空
        "age": 28,            // 数字,0-150
        "email": "zhangsan@example.com" // 字符串,符合邮箱格式
      }
    ]
  }
}
响应体 JSON 结构校验树 响应体 (JSON) code: number message: string data: object timestamp: string items: array total: number page: number items[0]: object items[1]: object 校验策略:字段存在性 → 类型校验 → 值范围校验 → 嵌套结构递归校验

3.5 接口校验的 Testing 断言模式

在 Go 的 testing 包中,接口校验通常封装为以下模式:

// 通用 HTTP 响应校验函数
func assertResponse(t *testing.T, resp *http.Response, expectedStatus int) {
    t.Helper()
    if resp.StatusCode != expectedStatus {
        t.Errorf("期望状态码 %d,实际 %d", expectedStatus, resp.StatusCode)
    }
    // 确保响应体可读
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        t.Fatalf("读取响应体失败: %v", err)
    }
    // 解析 JSON
    var result map[string]interface{}
    if err := json.Unmarshal(body, &result); err != nil {
        t.Fatalf("JSON 解析失败: %v", err)
    }
    // 校验业务状态码
    if code, ok := result["code"].(float64); ok {
        if int(code) != 200 {
            t.Errorf("业务状态码异常: %v", code)
        }
    }
}
压测集成建议: 在压测脚本(如 k6)中,使用 check() 函数同时校验状态码、响应时间和 JSON 字段。例如:check(res, { 'status is 200': (r) => r.status === 200, 'body has id': (r) => r.json().id !== undefined })。

3.6 本章小结

  • HTTP 请求方法决定操作语义,压测用例必须匹配接口设计(GET 查、POST 建、PUT 改、DELETE 删)。
  • 状态码是接口校验的第一道防线:2xx 成功、4xx 客户端错误、5xx 服务端错误。
  • 请求头携带认证、格式、幂等等元信息,压测中需动态生成或管理。
  • 响应体校验需覆盖字段存在性、类型、值范围与嵌套结构,避免只校验状态码。
  • Testing 驱动压测的核心:将 HTTP 协议知识转化为可重复执行的断言逻辑。