RESTful API 设计规范速查表 - REST API 接口设计大全

接口退化的原因很少是功能缺失,而是形状不统一:同一种资源在不同接口里换着名字,同一类错误一半返 200 带 errCode 一半返 500,前端每接一个都要重新判断一次。本表把 REST 接口的每一条决策点拆开:URL 如何表达资源层级与集合、用名词复数而非动词、过滤分页排序放查询参数还是路径、方法如何映射到幂等语义、状态码在什么场景取哪个、请求头承担哪些横切信息、响应体和错误体固定成什么形状、认证选哪一种。动手顺序也有讲究——先把资源模型和 URL 定下来,因为它决定权限与缓存怎么设计;再定错误结构,因为它决定前端兜底逻辑;响应包装最后定,因为改它成本最低。与方法表的分工是:那张表讲单条动词怎么选,这张表讲一整套接口保持形状稳定。

参考手册·共 46 条命令·最后更新 2026-07-21

典型使用场景

面向设计、评审或实现 HTTP 接口的开发者与后端工程师。表内把 REST 接口的约定一次理顺:URL 用名词复数表示集合、用 ID 定位单个资源,查询参数负责过滤、分页与排序;HTTP 方法各司其职,GET 安全且幂等、PUT 与 DELETE 幂等、POST 不幂等,PATCH 用于部分更新,HEAD 只取响应头,OPTIONS 承担 CORS 预检。状态码部分强调语义边界:401 是没认证、403 是认证了但没权限,400 是格式问题、422 是字段语义校验失败,409 用于重复创建冲突,429 表示触发限流。请求头与认证一节覆盖 JSON 协商、Bearer Token / JWT、API Key 与 OAuth 2.0 授权码模式,另有 If-None-Match 配合 ETag 做条件请求。响应结构推荐用 data + meta 的统一包裹,错误统一为 error.code 与 error.message,分页既可用 body 里的 page/limit/total,也可用 Link 头;批量操作走 /users/batch 这类子资源端点,配合 201 + Location、RateLimit-Limit / Retry-After 等响应头,让客户端能可靠处理重试与配额。

URL 设计规范 6

/api/v1/users
资源集合(复数名词)
/api/v1/users/123
单个资源(ID 定位)
/api/v1/users/123/orders
子资源嵌套
/api/v1/users?role=admin
查询参数过滤
/api/v1/users?page=2&limit=20
分页参数
/api/v1/users?sort=-created_at
排序(- 表示降序)

HTTP 方法 8

GET /users
获取资源列表(安全、幂等)
GET /users/123
获取单个资源
POST /users
创建资源(非幂等)
PUT /users/123
完整更新资源(幂等)
PATCH /users/123
部分更新资源
DELETE /users/123
删除资源(幂等)
HEAD /users/123
只获取响应头,不返回 body
OPTIONS /users
查询支持的 HTTP 方法(CORS 预检)

常用状态码 12

200 OK
请求成功
201 Created
资源创建成功
204 No Content
成功但无返回内容(如 DELETE)
301 Moved Permanently
资源永久重定向
400 Bad Request
请求参数错误或格式不合法
401 Unauthorized
未认证(缺少或无效凭证)
403 Forbidden
已认证但无权限访问
404 Not Found
资源不存在
409 Conflict
资源冲突(如重复创建)
422 Unprocessable Entity
语义错误(字段校验失败)
429 Too Many Requests
请求频率超限(触发限流)
500 Internal Server Error
服务器内部错误

请求头 5

Content-Type: application/json
请求体为 JSON 格式
Accept: application/json
期望响应为 JSON
Authorization: Bearer <token>
Bearer Token 认证头
If-None-Match: "etag"
条件请求(ETag 缓存校验)
X-API-Key: abc123
自定义 API Key 认证

响应格式 5

{ "data": [...], "meta": {...} }
标准列表响应结构
{ "data": {...} }
单资源响应结构
{ "error": { "code": "...", "message": "..." } }
错误响应结构
{ "page": 2, "limit": 20, "total": 100 }
分页元信息
Link: <url>; rel="next"
分页链接头(RFC 5988)

认证方式 5

Authorization: Basic base64(user:pass)
HTTP 基本认证
Authorization: Bearer <jwt>
Bearer Token / JWT 认证
X-API-Key: <key>
API Key 认证(自定义头)
?api_key=<key>
API Key 认证(查询参数)
OAuth 2.0
授权码模式(authorization code flow)

最佳实践 5

幂等性设计
GET/PUT/DELETE 应幂等,多次调用结果一致
POST 创建返回 201 + Location
创建成功返回 201 和资源 URI
批量操作: POST /users/batch
批量创建/更新使用子资源端点
RateLimit-Limit / Retry-After
限流响应头告知客户端配额
HATEOAS
响应中包含相关资源链接(超媒体驱动)

参数矩阵

参数作用示例
/api/v1/users资源集合路径,名词用复数/api/v1/users
/api/v1/users/123用 ID 定位单个资源/api/v1/users/123
/api/v1/users/123/orders子资源嵌套路径/api/v1/users/123/orders
?role=admin查询参数过滤资源/api/v1/users?role=admin
?page=2&limit=20分页参数/api/v1/users?page=2&limit=20
?sort=-created_at排序参数,前缀 - 表示降序/api/v1/users?sort=-created_at
GET /users获取资源列表,安全且幂等GET /users
POST /users创建资源,非幂等POST /users
PUT /users/123完整更新资源,幂等PUT /users/123
PATCH /users/123部分更新资源PATCH /users/123
DELETE /users/123删除资源,幂等DELETE /users/123
HEAD /users/123只获取响应头,不返回 bodyHEAD /users/123
OPTIONS /users查询支持的方法,用于 CORS 预检OPTIONS /users
200 OK请求成功GET /users/123 → 200
201 Created资源创建成功,配合 Location 头POST /users → 201 + Location
204 No Content成功但无返回内容,如删除DELETE /users/123 → 204
301 Moved Permanently资源永久重定向GET /old → 301
400 Bad Request请求参数错误或格式不合法POST /users → 400
401 Unauthorized未认证,缺少或无效凭证无 Authorization 头 → 401
403 Forbidden已认证但无权限访问普通用户访问管理接口 → 403
404 Not Found资源不存在GET /users/999 → 404
409 Conflict资源冲突,如重复创建重复注册同名账号 → 409
422 Unprocessable Entity字段校验失败的语义错误邮箱格式非法 → 422
429 Too Many Requests请求频率超限,触发限流高频调用 → 429
500 Internal Server Error服务器内部错误未捕获异常 → 500
Content-Type: application/json声明请求体为 JSONContent-Type: application/json
Accept: application/json期望响应为 JSONAccept: application/json
Authorization: Bearer ***Bearer Token / JWT 认证Authorization: Bearer <token>
If-None-Match: "etag"条件请求,用 ETag 校验缓存If-None-Match: "v1"
X-API-Key: ***自定义头携带 API Key 认证X-API-Key: <key>
{ "data": [...], "meta": {...} }标准列表响应结构{ "data": [], "meta": {} }
{ "data": {...} }单资源响应结构{ "data": { "id": 1 } }
{ "error": { "code", "message" } }统一错误响应结构{ "error": { "code": "INVALID_ARG" } }
{ "page", "limit", "total" }分页元信息{ "page": 2, "limit": 20, "total": 100 }
Link: <url>; rel="next"分页链接头,便于客户端翻页Link: </users?page=3>; rel="next"
Authorization: Basic ***HTTP 基本认证Authorization: Basic <base64>
?api_key=<key>查询参数携带 API Key/users?api_key=<key>
OAuth 2.0 授权码模式第三方授权的标准流程authorization code flow
POST /users/batch批量创建/更新使用子资源端点POST /users/batch
RateLimit-Limit / Retry-After限流响应头,告知配额与重试时机Retry-After: 30
HATEOAS响应中包含相关资源链接{ "links": { "orders": "..." } }

易错点与避坑指南

现象客户端收到 401 后不断重试,永远进不去

原因接口把「凭证无效」也返回成了 401,客户端分不清该重新登录还是该重试

处置未认证返回 401,已认证但无权限返回 403,让客户端能走不同的处理分支

现象前端把 400 当成字段校验失败来展示,实际是请求体格式就不对

原因格式错误与语义错误混用了同一个状态码

处置格式或语法错误用 400,字段级业务校验失败用 422,并在 error.code 中区分

现象重复提交同一个创建请求,数据库里出现两条相同记录

原因POST 本身不幂等,客户端超时重试时服务端无法识别重复

处置用 409 Conflict 表达重复创建,并要求客户端带幂等键或先查询再创建

现象PUT 更新后客户端没传的字段被清空了

原因PUT 被当作完整替换处理,缺失字段按默认值写回

处置语义上只需要改部分字段时改用 PATCH,只接受实际提交的字段

现象改用 PATCH 后客户端仍按完整对象提交,服务端行为与 PUT 一样

原因接口实现忽略部分更新语义,全量覆盖了记录

处置在 PATCH 处理里只读取请求体中出现的键做更新,其余字段保持不变

现象集合路径写成 /user 而不是 /users,客户端按同一规则解析时全错

原因URL 命名未统一,资源集合与单个资源没有区分

处置统一用名词复数表示集合、ID 定位单个资源,并把版本号固定在 /v1/ 前缀里

现象触发限流后客户端没有退避,接口雪崩式被压垮

原因429 响应里没有告诉客户端该等多久,客户端只能密集重试

处置在 429 响应中带上 Retry-After 与 RateLimit-Limit,让客户端按提示退避重试

排障路径

  1. 1确认某个端点到底支持哪些 HTTP 方法

    OPTIONS /users

    预检请求会返回允许的方法列表,也是排查跨域与方法限制的第一个入口。

  2. 2检查当前客户端手里的缓存副本是否还有效

    If-None-Match: "etag"

    带上上次的 ETag 请求,内容没变时服务端返回 304,省掉整个响应体传输。

  3. 3定位分页到底从哪一页开始、总量是多少

    /api/v1/users?page=2&limit=20

    响应里的 { "page", "limit", "total" } 可核对服务端与客户端的页码约定是否一致。

  4. 4按创建时间倒序核对列表默认排序

    /api/v1/users?sort=-created_at

    前面的 - 表示降序;去掉 - 则是升序,可确认排序方向是否符合接口约定。

  5. 5确认创建成功后资源的新地址

    POST /api/v1/users

    成功应返回 201,响应头里的 Location 给出新建资源的 URI,可直接用它跟进一次 GET。

  6. 6验证鉴权失败到底属于哪一类

    GET /api/v1/users/123

    无凭证得到 401、带凭证仍被拒得到 403,据此判断该修客户端凭证还是服务端授权。

  7. 7确认批量操作端点的行为

    POST /users/batch

    批量走独立子资源端点而非在集合上叠加方法,响应里应逐条给出成功与失败明细。

命令示例

列表接口:查询参数 + 分页 + 排序一次表达清楚

GET /api/v1/users?role=admin&page=2&limit=20&sort=-created_at Accept: application/json Authorization: Bearer <token>

集合用复数名词、ID 定位用子路径,过滤/分页/排序全部走查询参数(sort 前加 - 表示降序)。响应体统一包在 data 里,分页信息放 meta,客户端只需认一套结构。

输出

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [ { "id": 123, "role": "admin", "created_at": "2026-07-19T10:30:00Z" } ],
  "meta": { "page": 2, "limit": 20, "total": 100 }
}

创建资源返回 201 + Location

POST /api/v1/users Content-Type: application/json { "name": "tom" }

POST 创建成功必须回 201 并用 Location 头指明新资源位置,客户端不必再解析 body 拼 URL。用 200 返回创建结果会让缓存和监控都无法区分「创建」与「查询」。

输出

HTTP/1.1 201 Created
Location: /api/v1/users/456

{ "data": { "id": 456, "name": "tom" } }

用 ETag 做条件请求省掉整包传输

GET /api/v1/users/123 If-None-Match: "a1b2c3d4"

客户端把上次拿到的 ETag 原样回传,内容没变时服务端回 304 且不带 body。对频繁轮询的移动端接口,流量能降到零,省带宽也省服务端序列化开销。

输出

HTTP/1.1 304 Not Modified
ETag: "a1b2c3d4"

错误响应用固定结构,区分 401 与 403

GET /api/v1/users/999 Authorization: Bearer <expired-token>

401 表示凭证缺失或失效(客户端该去登录/刷新 token),403 表示凭证有效但权限不足(重试无用)。把两者混成一个 401 会让客户端陷入无限重试。

输出

HTTP/1.1 403 Forbidden

{
  "error": {
    "code": "FORBIDDEN",
    "message": "token lacks scope users:read"
  }
}

限流后按 Retry-After 退避

GET /api/v1/users # 触发限流时: # HTTP/1.1 429 Too Many Requests # RateLimit-Limit: 100 # Retry-After: 30

429 必须带 Retry-After,客户端按它退避重试;否则客户端只能硬编码一个猜测值,在限流期间把压力越叠越大。写接口的客户端还要把 429 计入重试预算而不是当失败放弃。

常见坑与注意事项

  • 分页游标(cursor / after / since)依赖排序字段的稳定性:一旦有新记录插入或同值记录,next 游标会失效或漏数据,导致客户端卡在同一页或丢行;优先用「(created_at, id) 复合游标」并给一致性快照。
  • POST 创建若没有幂等键(Idempotency-Key)或唯一约束,客户端超时重试会重复下单、重复扣款;支付类写接口必须保证重试安全,否则一次网络抖动就是真金白银的损失。
  • 用本地时间存时间戳会丢时区与精度:跨时区客户端会把 2026-07-19T10:30:00Z 读成本地时间,跨日订单对不上账;统一用 UTC RFC 3339 带 Z 或偏移量,金额与数量一律用整数最小单位。
  • 在 URL 查询参数里传 API Key(?api_key=)会被浏览器历史、代理日志和 Referer 头记录下来,等同于把凭证公开;请改用 X-API-Key 或 Authorization 头。
  • PUT 被定义为幂等的整体替换,只传部分字段会把未传字段清空;客户端想局部更新必须用 PATCH,否则会静默抹掉别的字段。
  • DELETE 声称幂等,但对同一资源先删后重建会让第二次 DELETE 返回 404,客户端若把 404 当失败就会误报;确认删除结果需回查时用 204 或带回执字段。

提示

  • URL 使用名词复数表示资源集合,如 /users 而不是 /user。
  • GET 请求应该是安全的,不改变服务器状态;PUT/DELETE 应是幂等的。
  • PUT 是完整替换,PATCH 是部分更新,根据场景选择。
  • API 版本放在 URL 路径中(/v1/)或请求头中(Accept-Version)。
  • 错误响应应包含错误码、消息和可选的详情字段,方便客户端处理。
  • 分页统一一种风格并写进文档:offset 分页用 limit/offset,cursor 分页用 cursor/limit 且游标不透明,大数据量表优先 cursor 避免深翻页拖垮数据库。
  • 错误体把字段错误放到 details 里做字段级映射(如 {"email": "格式非法"}),前端才能定位到输入框,而不是只弹一句"参数错误"。
  • 幂等键用客户端生成的 UUID 而非请求体字段,且键要绑定到操作类型:同一键复用到不同端点应被拒绝,否则去重逻辑会误伤。

常见问题

401、403、404 到底怎么选?

按「鉴权还是授权还是找不到」分:401 Unauthorized 是没通过认证——缺少凭证、token 无效或已过期,客户端的解法是带上或刷新凭证。403 Forbidden 是通过了认证但权限不足,凭证没问题,是这个主体不允许碰这个资源,重试无用。404 Not Found 是资源不存在,包括刻意隐藏存在性时也用它,避免泄露「资源存在但你无权」的信号。三者的重试语义完全不同:401 可重试(换 token)、403 不可重试、404 需要换 URL 或 ID。POST 创建重复数据则不是 401/403/404,而是 409 Conflict。

PUT 和 PATCH 都能改数据,接口设计时该怎么选?

看替换语义:PUT /users/123 是完整更新,必须提交该资源的完整表示,调用两次结果一致(幂等);PATCH /users/123 是部分更新,只传要改的字段,其余保持不变。同样属于幂等设计的还有 DELETE /users/123——重复删除结果一致。另外 GET 必须安全,不能改变服务器状态,POST /users 用来创建,属于非幂等。工程上选 PATCH 更省事,客户端只发改动的字段;选 PUT 则更利于缓存与校验,但一旦有字段被漏传就会丢数据,所以很多团队在 schema 里区分「全量必填」和「增量可空」两套表示。

参数不合法到底该返回 400 还是 422?

按错误发生的位置分层:400 Bad Request 用于请求参数错误或格式不合法——JSON 解析不了、Content-Type 不对、语法层面就坏了,服务器连「内容」都没读进去。422 Unprocessable Entity 用于语义错误,字段校验失败:结构解析得进去,但 email 格式不对、age 越界、状态取值非法。这类区分对客户端有意义,因为 400 意味着「别再原样重发」,422 意味着「把报错字段改了再发」。二者都应配合统一的错误结构 { "error": { "code": "...", "message": "..." } } 返回,方便客户端按 code 分支处理。

创建接口返回什么?批量写入和限流怎么处理?

创建成功应返回 201 Created 而不是 200,并带上 Location 头指向新资源 URI;后续取该资源用 HEAD /users/123(只取响应头)或 GET 取 body。成功但无内容时用 204 No Content,删除场景最典型。批量创建/更新不要硬塞进普通 POST,用子资源端点 POST /users/batch。触发限流时返回 429 Too Many Requests,并用 RateLimit-Limit 告知配额、Retry-After 告知何时重试,客户端据此退避。响应里带上相关资源链接(HATEOAS)能让客户端跟着链接发现下一步动作,而不是把 URL 硬编码。

几种认证方式怎么选?

按客户端类型和信任度分。Authorization: Bearer <token> 适合前后端分离的 SPA,token 可以是 JWT,权限信息自包含,Authorization: Basic <base64> 只是 base64 编码的账号密码,安全性低,适合内网或临时调试。X-API-Key: <key> 走自定义头,服务端到服务端调用最常见;把 key 放进 ?api_key=<key> 查询参数虽然方便但会进访问日志和 Referer,生产环境应避免。需要第三方用户授权的用 OAuth 2.0 授权码模式。配套请求头有 Content-Type: application/json、Accept: application/json,以及 If-None-Match: "etag" 做条件请求,靠 ETag 命中缓存省带宽。

官方参考来源

下方为命令对应的官方权威文档,供你核对最新用法与深入查阅。

由 巧匠 维护

公开更新于 2026年7月21日,内容持续校对官方文档。

联系我们

命令或描述有误?提交反馈、商务合作或产品建议都可发送邮件给我们。

联系我们