跳转到内容
GitHub

主题 / 后端与数据

16 接口契约与事件

对外接口和事件怎么定契约:接口风格、OpenAPI 契约优先与 lint、错误格式、命名、分页、版本与破坏性变更、幂等、并发写、事件与 webhook 发布、实时推送、MCP 服务端和命令行的机器可读输出。

草稿复核于 2026-11-14 · 下次复核 2027-05-1437 条规则 · 硬约束 23 条在 GitHub 上修改

一页结论

  1. 先定契约,再写实现。 普通 HTTP 接口默认 REST + OpenAPI;契约文件放在仓库里,和实现在同一个 PR 里改,CI 跑 lint 和破坏性变更检测。GraphQL、gRPC/Connect、WebSocket 要有客观理由并记下来。
  2. OpenAPI 默认 3.1。 3.2 已正式发布,但生成器、网关、lint 工具支持不齐,用 3.2 新特性前先在自己的工具链上验证。
  3. 错误统一 RFC 9457(application/problem+json)。type 和 code 是给程序判断的稳定标识;title、detail 给人看,程序不解析。不泄露堆栈、SQL、令牌。
  4. 同一个接口域只用一种命名风格。 新接口的 JSON 字段默认 camelCase,用 lint 强制。
  5. 列表必须分页。 有默认值和上限的 limit、确定的排序(带唯一的兜底字段)、不透明的游标;过滤和排序只认白名单字段。
  6. 会被重试的写操作要幂等。 用 Idempotency-Key(IETF 草案,尚未成为 RFC)或客户端自定 ID + PUT。缺键 400、同键不同请求体 422、第一次请求还在处理 409。幂等记录要和业务变更一起持久化。
  7. 防丢失更新用强 ETag + If-Match。 不匹配 412,缺前置条件 428,业务状态冲突 409;服务端做原子比较更新。
  8. 破坏性变更不能悄悄发。 CI 用 oasdiff 对比上一个发布的契约;破坏性改动走新主版本或经批准的迁移计划;废弃用 Deprecation / Sunset 响应头通知。
  9. 事件和投递分开。 事件用 CloudEvents 信封、AsyncAPI 描述;至少一次投递,重发保持同一个 (source, id),消费方去重;不承诺全局有序和恰好一次。
  10. 对外 webhook 按 Standard Webhooks 签名:签 webhook-id.webhook-timestamp.原始请求体,支持多签名轮换密钥;有限次退避重试、死信和手动重放;用户填的回调地址做 SSRF 防护。
  11. MCP 以当前正式版本为准,用官方 SDK。 核实时(2026-11-14)当前版本是 2026-07-28:去掉了初始化握手,每个请求自带协议版本,可用 server/discover 预先协商;兼容 2025-11-25 及更早的旧客户端要单独测试。HTTP 传输上开了授权的,服务端按 OAuth 2.1 资源服务器实现:提供受保护资源元数据,校验令牌受众,不转发令牌。
  12. 命令行工具人机两用。 --json 时标准输出只有 JSON,诊断走标准错误;退出码公开稳定;支持非交互运行。

规则

级别
检查方式
显示 37 条
API-001软指导检查:人工对外提供服务的后端

普通 HTTP 接口默认用 REST + OpenAPI;改用 GraphQL、gRPC/Connect 或 WebSocket 时,把客观理由写进设计记录

怎么检查:评审新服务的设计记录(ADR),看非 REST 方案是否写了需求依据和取舍
为什么、来源
为什么:REST + OpenAPI 的客户端、网关、调试工具最普及;为少数场景引入别的风格,会增加运维和接入成本。

常见的客观理由:

  • GraphQL:前端需要频繁自由组合查询,且能做查询复杂度限制;
  • gRPC / Connect:内部服务间强类型调用、需要流式;浏览器和第三方调用方优先 Connect 或 REST,不强制原生 gRPC;
  • WebSocket:真正的双向实时交互。只是服务端单向推送时用 SSE(见 API-031)。
API-002硬约束检查:自动对外提供服务的后端

对外 HTTP 接口必须有放在仓库里的 OpenAPI 契约文件,接口改动与契约改动在同一个 PR 里提交

怎么检查:CI 检查契约文件存在;用基于 schema 的测试(见 04)验证实现的响应符合契约
为什么、来源
为什么:截图、口头约定和聊天记录没法被工具检查,客户端和 SDK 也没法据此生成。
  • 契约是唯一来源,生成的客户端、服务端桩代码只读(各语言做法见 10–14)。
  • 从代码注解导出契约也可以,但导出的文件必须提交进仓库、参与 lint 和破坏性检测,不能只在运行时生成。
  • 契约引用的 schema 随仓库提交,不在构建或运行时去拉远程 $ref。
API-003硬约束检查:自动对外提供服务的后端

每个操作必须有唯一且稳定的 operationId,每个响应写明状态码、Content-Type 和 schema,并给出成功和错误示例

怎么检查:Spectral 规则集启用 operationId 唯一、响应必须有 schema 和示例等规则,CI 中以错误级别运行
为什么、来源
为什么:生成的 SDK 方法名取自 operationId,改了就是破坏性变更;没有写明的响应,调用方和 Agent 只能猜。
API-004硬约束检查:自动对外提供服务的后端

契约 lint 规则集放在仓库里,CI 对每次契约改动运行,错误级别的问题阻断合并

怎么检查:CI 运行 spectral lint(或所选工具),检查退出码
为什么、来源
为什么:命名、分页、错误格式这些约定只写在文档里会慢慢走样,lint 才能让每次改动都遵守。

本主题里能机器判定的约定(命名风格、分页参数、错误响应格式、operationId)都应写成 lint 规则。

API-005软指导检查:半自动对外提供服务的后端

OpenAPI 默认用 3.1;要用 3.2 的新特性,先确认所用的 lint、diff、生成器和网关都支持

怎么检查:升级前在 CI 里用全部工具链跑一遍 3.2 契约,并编译生成的客户端
为什么、来源
为什么:3.2 已正式发布,但规范发布不等于工具支持;部分生成器对 3.1 的支持都还标为测试版。

3.2 新增了 QUERY 方法描述、流式媒体类型等。只有确实需要这些特性时才升级。

API-006软指导检查:人工对外提供服务的后端

按业务资源和动作建模接口,不直接暴露数据库表名、内部函数名和内部枚举

怎么检查:评审新接口时对照数据模型,看路径和字段是否只是表结构的照搬
为什么、来源
为什么:接口一旦和表结构绑死,改一次表就要改一次公开契约。
API-007硬约束检查:半自动对外提供服务的后端

GET、HEAD 请求不得产生业务副作用;不能归为标准方法的业务动作用 POST,并在契约里写明副作用和是否幂等

怎么检查:评审时检查 GET 处理函数是否写库或调用有副作用的服务;契约里自定义动作必须有副作用说明
为什么、来源
为什么:HTTP 规定 GET、HEAD 是安全方法,缓存、预取、爬虫和重试都会假定它们没有副作用。

自定义动作可以写成 POST /v1/orders/{id}:cancel,也可以建模成子资源 POST /v1/orders/{id}/cancellations。选一种并在整个接口域里统一,不要混用。

API-008硬约束检查:自动对外提供服务的后端

同一个接口域里的 JSON 字段、查询参数和错误码各只用一种命名风格,并用 lint 强制

怎么检查:Spectral 的 casing 规则检查 schema 属性名和参数名
为什么、来源
为什么:同一个接口里 createdAt 和 created_at 并存,调用方和生成器都会出错,事后统一就是破坏性变更。
  • 新接口的 JSON 字段和查询参数默认用 camelCase(与浏览器和 TypeScript 客户端一致,也是 Microsoft 接口指南的约定);已有接口或生态普遍用 snake_case 的,沿用原风格。
  • 错误码(code)用全大写下划线,如 ORDER_NOT_FOUND。
  • 枚举值、事件字段同样遵守本接口域的风格。
  • 已经公开的字段不为了统一风格而改名。
API-009软指导检查:自动对外提供服务的后端

时间字段用 RFC 3339 格式并带时区偏移(推荐 UTC),在 schema 里标 format: date-time

怎么检查:Spectral 规则检查名称像时间的字段是否声明了 date-time 格式
为什么、来源
为什么:不带时区的时间在跨时区部署和客户端解析时会出错。
API-010硬约束检查:半自动对外提供服务的后端

返回列表的接口必须分页:limit 有默认值和上限,排序确定并以唯一字段兜底

怎么检查:lint 检查列表操作有分页参数和上限;测试用排序字段相同的数据验证翻页不重不漏
为什么、来源
为什么:不分页的列表会随数据增长拖垮服务;排序不确定时,翻页会重复或漏掉数据。
  • 数据量大或变化快的列表用游标分页;offset 只用于数据少、基本不变的表或确实需要跳页的场景。
  • 例:GET /v1/orders?limit=50&sort=-createdAt,id&cursor=...,最后一个 id 保证排序唯一。
API-011软指导检查:半自动对外提供服务的后端

游标对调用方不透明,绑定生成它的查询条件和调用者;条件不一致时拒绝,不承诺快照一致

怎么检查:测试篡改游标、换过滤条件或换用户复用游标,应返回 400;契约文档写明翻页期间数据增删的行为
为什么、来源
为什么:调用方解析或拼接游标后,服务端就没法改实现;跨用户复用的游标还可能越权。
  • 游标可以签名防篡改;base64 编码不是保护。
  • 不承诺游标内容和长度。
  • 除非实现了快照,翻页期间有增删时不承诺零重复、零遗漏。
API-012硬约束检查:半自动对外提供服务的后端

过滤、排序、字段选择、展开参数只接受白名单字段,不允许传 SQL 片段或任意表达式

怎么检查:契约里这些参数用枚举声明;测试传非白名单字段应返回 400
为什么、来源
为什么:任意表达式会导致注入,也会让查询成本不可控。
API-013软指导检查:人工对外提供服务的后端

批量操作在契约里写明是否全有或全无、逐项结果的格式和幂等粒度

怎么检查:评审批量接口的契约,看是否有逐项状态字段和部分失败的说明
为什么、来源
为什么:部分成功时只看 HTTP 状态码,调用方不知道哪些成功了、哪些可以重试。

部分成功时在响应体里给逐项结果,如 items[{clientRef, status, result, error}];用 200 还是 207 在接口域里统一。

API-014软指导检查:半自动对外提供服务的后端

可能超时的长任务返回 202 和一个任务资源,可查询状态、终态结果和失败原因,并写明取消方式和结果保留期

怎么检查:端到端测试覆盖任务提交、查询、完成、失败、取消
为什么、来源
为什么:长时间占着连接等结果,断线后调用方无法恢复,也会被网关超时打断。
API-015硬约束检查:自动对外提供服务的后端

4xx 和 5xx 响应使用 RFC 9457 格式(application/problem+json),status 与 HTTP 状态码一致;不用 200 包装失败

怎么检查:lint 检查所有错误响应引用统一的 Problem schema 和媒体类型;接口测试校验错误响应体
为什么、来源
为什么:统一的错误格式让客户端、网关和重试逻辑能通用处理;200 {success:false} 会骗过所有按状态码工作的中间件。
  • 标准成员:type(问题类型 URI,缺省为 about:blank)、title、status、detail、instance。
  • 扩展成员按需加,如 code(稳定错误码)、errors(字段级校验错误)、retryable。客户端必须忽略不认识的扩展成员。
  • RFC 9457 取代了 RFC 7807,新代码按 9457 写。
API-016硬约束检查:半自动对外提供服务的后端供别人引用的库或 SDK

程序只按 type 或 code 判断错误,不解析 title 和 detail;错误码登记在错误目录里,发布后不改含义

怎么检查:契约里 code 用枚举并与错误目录比对;评审客户端代码时查找对 detail 文本的匹配
为什么、来源
为什么:RFC 9457 明确建议不解析 detail;它可能被本地化或改写,靠文本判断的客户端会突然失效。
API-017硬约束检查:半自动对外提供服务的后端

错误响应不得包含堆栈、SQL、内部主机名、令牌和个人信息;instance 只用作追踪标识

怎么检查:测试触发各类服务端异常,扫描错误响应体中的堆栈和 SQL 特征
为什么、来源
为什么:错误信息是常见的信息泄露渠道,攻击者靠它探测内部结构。
API-018软指导检查:半自动对外提供服务的后端

429 和 503 响应带 Retry-After;retryable 只表示原请求可以原样重放,写操作是否能重试还要看幂等策略

怎么检查:故障测试检查限流和降级响应的响应头;评审错误目录里 retryable 的取值
为什么、来源
为什么:没有重试提示,客户端会立刻重试造成雪崩;把不幂等的写操作标为可重试会造成重复执行。
API-019硬约束检查:半自动对外提供服务的后端

有副作用、且调用方可能重试的 POST 操作必须在契约里声明幂等方式:Idempotency-Key 或客户端自定 ID + PUT

怎么检查:lint 检查非幂等方法是否声明了 Idempotency-Key 请求头或说明了替代方式;评审支付、下单、发消息等操作
为什么、来源
为什么:网络超时后调用方不知道请求是否成功,只能重试;没有幂等就会重复扣款、重复下单。

Idempotency-Key 由 IETF httpapi 工作组的草案定义,核实时(2026-11-14)仍是草案第 08 版(2026-10-22),尚未成为 RFC,按草案语义实现,并关注后续变化。

API-020硬约束检查:自动对外提供服务的后端

使用 Idempotency-Key 时,缺键(且要求必填)返回 400,同键不同请求体返回 422,第一次请求仍在处理返回 409;同键同请求体已完成的,返回第一次的结果

怎么检查:契约测试逐一构造这四种情况并校验状态码和响应体
为什么、来源
为什么:这是草案规定的语义;状态码统一后,客户端才能区分「我用错了键」和「请稍后再查」。

错误响应用 RFC 9457 格式,type 区分这几类情况。

API-021硬约束检查:半自动对外提供服务的后端

幂等键的作用域绑定调用者和操作,并记录请求体指纹;幂等记录与业务变更一起持久化,有效期写进契约

怎么检查:并发重复请求测试和进程崩溃测试,验证只执行一次;评审幂等存储是否持久化
参考值:有效期 24 小时是常见的产品取值,不是标准要求。
为什么、来源
为什么:只存在内存里的幂等键,重启或多实例时就失效;不比对请求体,会把两个不同的请求当成一个。
  • 作用域例:租户 + 调用者 + 方法 + 路由 + 键。
  • 有效期只是重放保护窗口,过期后不保证去重;绝不能重复的业务事实(如同一笔付款)还要靠数据库唯一约束。
  • 处理中状态要有超时回收,不能永久卡住。
  • 存储与事务的实现见 17。
API-022硬约束检查:自动对外提供服务的后端

可能丢失更新的写操作用强 ETag + If-Match 做前置条件:不匹配返回 412,要求带前置条件却没带返回 428,业务状态冲突返回 409;弱 ETag 不用于 If-Match

怎么检查:双客户端竞争测试:两个客户端用同一个 ETag 先后更新,后者必须得到 412
为什么、来源
为什么:两个人同时编辑,后保存的会静默覆盖前一个人的改动。If-Match 按 HTTP 规定只做强比较。
  • 服务端必须用原子的比较并更新(如带版本号条件的 UPDATE),不能先查 ETag 再无条件更新。
  • 428 来自 RFC 6585。
  • 也可以用领域版本号字段代替 ETag,语义相同。数据库层的乐观锁见 17。
API-023硬约束检查:自动对外提供服务的后端供别人引用的库或 SDK

CI 用 oasdiff 对比上一个发布版本的契约;检测到破坏性变更时阻断,除非走新主版本或附上经批准的迁移计划

怎么检查:CI 运行 oasdiff breaking <基线契约> <新契约> 并按退出码阻断;豁免要在 PR 里写明并经负责人批准
为什么、来源
为什么:删字段、改类型、改必填,单个服务的测试全绿,调用方却会出错。

工具查不出的破坏性变化要人工评审:

  • 新增枚举值(按穷举处理的客户端会出错);
  • 默认值、排序、分页行为、限流、权限语义的变化;
  • 字段含义变化但类型没变。 客户端一侧要容忍未知字段和未知枚举值。
API-024软指导检查:人工对外提供服务的后端

每个接口域只选一种版本策略并写进接口说明;默认用路径主版本(如 /v1)

怎么检查:评审接口说明里是否写明版本策略、新版本发布后旧版本的支持期
参考值:GitHub 承诺旧版本在新版本发布后至少支持 24 个月,可作参考,不是通用要求。
为什么、来源
为什么:版本放路径、放请求头、放日期混用,调用方无从判断自己在用哪个版本。
  • 路径主版本简单直观,适合大多数产品。
  • 已有大量 SDK 的公开平台可以用日期版本请求头(如 GitHub 的做法)。
  • info.version 是接口文档的版本,openapi 字段是规范的版本,两者不要混淆。
API-025硬约束检查:自动对外提供服务的后端

公开接口废弃时,发布迁移说明,并在响应里带 Deprecation 头,确定下线日期后再带 Sunset 头

怎么检查:契约测试检查被标为 deprecated 的操作响应带这两个头
为什么、来源
为什么:只在发布说明里写「以后删除」,调用方多半看不到;标准响应头能被客户端和监控自动发现。
  • Deprecation 由 RFC 9745 定义,值是 @ 加 Unix 秒数;Sunset 由 RFC 8594 定义,值是 HTTP 日期。两者格式不同。
  • 同时在契约里把操作标为 deprecated: true。
API-026软指导检查:半自动对外提供服务的后端

对外发布的事件用 CloudEvents 信封,type 稳定且带业务版本,每个 type 有独立 schema,并在事件目录里登记

怎么检查:CI 用 JSON Schema 校验事件样例;事件目录(可用 AsyncAPI 描述)与代码里的事件类型比对
为什么、来源
为什么:各服务自定事件字段,消费方只能逐个适配;没有 schema 的事件改起来没人知道会影响谁。
  • 必填属性:specversion、id、source、type。
  • 事件名用过去时表达已发生的事实,如 com.example.orders.order.confirmed.v1;不要把命令伪装成事件。
  • 三种版本别混:specversion 是信封规范版本,type 后缀或 dataschema 是业务载荷版本,聚合版本号是对象的状态序号。
  • 事件目录写明:负责人、含义、schema、是否含个人信息、顺序键、投递保证、保留期、重放方式、兼容策略。
API-027硬约束检查:半自动对外提供服务的后端

事件按至少一次投递设计:重发时保持同一个 (source, id),消费方据此去重;写明顺序范围,不承诺全局有序和恰好一次

怎么检查:测试重复投递和乱序投递,验证消费方结果不变;评审事件目录里的顺序和投递保证说明
为什么、来源
为什么:网络和重试决定了重复不可避免;每次重发换 id,消费方就没法去重。
  • 需要顺序时按聚合对象排序,事件里带聚合 id 和版本号。
  • 关键事件和业务变更的一致性靠 outbox,消费方去重状态靠 inbox,表设计见 17。
API-028硬约束检查:自动对外提供服务的后端

对外发布的 webhook 按 Standard Webhooks 签名:带 webhook-id、webhook-timestamp、webhook-signature,对「id.时间戳.原始请求体」签名,每个接收端单独密钥,轮换期间同时附新旧两个签名

怎么检查:用 Standard Webhooks 官方验签库写测试,验证签名可通过、篡改请求体或时间戳后失败、轮换期间新旧密钥都能验证
参考值:规范建议载荷一般不超过约 20 KB;时间戳容忍窗口规范没有给定值,由接收方设定。
为什么、来源
为什么:不签名的 webhook 可以被伪造;签名不含时间戳就挡不住重放。
  • 默认用 HMAC-SHA256(v1);接收方不完全可信、需要只给公钥时用 Ed25519(v1a)。
  • webhook-id 在重试时不变,接收方用它去重;webhook-timestamp 是本次发送时间。
  • 发送的字节必须与签名的字节完全一致。
  • 只用 HTTPS;请求体保持较小,大内容给链接。
  • 接收第三方回调的一侧见 21。
API-029软指导检查:半自动对外提供服务的后端

webhook 投递失败时按指数退避加随机抖动重试,有总时长上限;持续失败后停用接收端并通知对方,提供投递记录和手动重放

怎么检查:故障注入测试:接收端返回 5xx、超时、410,检查重试节奏、停用和重放
参考值:Standard Webhooks 的示例重试计划持续约 3 天,是参考值。
为什么、来源
为什么:接收方短暂故障很常见;不重试会丢事件,无限重试又会打垮对方和自己。
  • 接收端返回 410 时停用该接收端;有 Retry-After 时遵守。
  • 2xx 只表示对方已收到,不代表业务处理成功。
  • 投递记录包括每次尝试的时间、状态码、耗时。
API-030硬约束检查:自动对外提供服务的后端

webhook 地址由用户填写时,发送前和每次跟随重定向时都校验目标地址,禁止回环、内网和云元数据地址

怎么检查:SSRF 测试用例:回环地址、内网段、元数据地址、指向内网的重定向和 DNS 重绑定都必须被拒绝
为什么、来源
为什么:用户可控的回调地址是典型的 SSRF 入口,可被用来探测和攻击内网服务。

私有化部署中客户要求投递到自己内网的,用显式配置的允许列表放行,不整体关闭校验。具体防护手段见 25。

另见:25 安全
API-031软指导检查:半自动对外提供服务的后端Web 前端

承诺断线可续传的 SSE 流,每条事件带 id,服务端从持久化的事件记录按 Last-Event-ID 续传;超出保留期时明确告知调用方重新同步

怎么检查:端到端测试断网重连、服务端重启、游标过期三种情况
为什么、来源
为什么:事件只存在进程内存里,重启或断线后就丢了;悄悄丢掉一段历史,客户端会以为数据完整。
  • 定期发注释行作心跳,防止中间代理断开空闲连接。
  • 浏览器原生 EventSource 不能自定义请求头,鉴权用 Cookie 或支持流式 fetch 的客户端。
  • 服务端单向推送用 SSE;需要双向交互时才用 WebSocket。
API-032软指导检查:半自动对外提供服务的后端调用大模型的应用

MCP 工具按用户任务设计,不把每个 REST 接口自动转成工具;每个工具有清楚的名称、描述和输入 schema,结构化输出声明输出 schema

怎么检查:静态检查工具清单:每个工具有描述、输入 schema 禁止多余字段;用固定任务集评测工具被选中和调用的正确率(见 24)
为什么、来源
为什么:工具太多、太碎,模型容易选错;描述不清,模型不知道何时用、出错后怎么办。
  • 描述写清:做什么、什么时候用、什么时候不用、是否修改数据、输入的格式和单位、失败后的安全下一步。
  • 单次输出有大小上限;结果多时分页、过滤或返回资源链接。
  • 长任务返回任务句柄,不阻塞等待。
  • 工具列表排序稳定。
API-033硬约束检查:自动对外提供服务的后端调用大模型的应用

MCP 工具执行中的业务错误放在工具结果里并标 isError;只有协议层的错误(未知工具、参数不合 schema 等)用 JSON-RPC 错误

怎么检查:协议测试:构造业务失败和协议错误两类请求,检查返回形式
为什么、来源
为什么:放在工具结果里的错误模型能看到并自行修正;当成协议错误返回,模型通常拿不到有用信息。
API-034硬约束检查:自动对外提供服务的后端调用大模型的应用

用官方 SDK 实现 MCP 协议层;声明支持哪些协议版本,并为每个声明支持的版本跑互通测试

怎么检查:CI 用各个声明版本的客户端连接服务,跑工具列表和调用测试
为什么、来源
为什么:新版协议与旧版差别很大,手写协议拼装容易出错;不测就声称兼容,旧客户端会在上线后才失败。
  • 核实时(2026-11-14)的当前版本是 2026-07-28:每个请求在 _meta 和 MCP-Protocol-Version 头里带协议版本,服务端逐个请求接受或拒绝,不支持时返回 UnsupportedProtocolVersionError 并列出支持的版本;客户端可调用 server/discover 预先获取版本和能力。
  • 2025-11-25 及更早的版本基于初始化握手,兼容它们要按规范的「向后兼容」一节实现并单独测试。
  • 被标为废弃的特性至少保留 12 个月(加急情况 90 天),升级前查看规范的废弃特性清单。
API-035硬约束检查:自动对外提供服务的后端调用大模型的应用

通过 HTTP 提供、需要授权的 MCP 服务,按 OAuth 2.1 资源服务器实现:提供受保护资源元数据,校验令牌是签发给本服务的,不接受也不转发其他令牌,令牌不放在 URL 里

怎么检查:测试用发给其他服务的令牌、过期令牌、放在查询参数里的令牌访问,都必须返回 401;检查受保护资源元数据端点可访问
为什么、来源
为什么:规范对这些要求用的是 MUST;不校验受众的服务会接受本该发给别的服务的令牌,转发令牌会造成代理混淆攻击。
  • MCP 的授权本身是可选的;一旦在 HTTP 传输上做,就按规范实现。标准输入输出传输不走这套流程,从环境中取凭据。
  • 令牌无效或过期返回 401 并带 WWW-Authenticate(含 resource_metadata);权限不足返回 403 和 insufficient_scope,一次给出当前操作需要的全部 scope。
  • 客户端注册优先 Client ID Metadata Documents,动态客户端注册已标为废弃,仅为兼容保留。
  • 令牌、会话、授权模型的通用规则见 19;本机运行的 MCP 服务的监听和防护见 32。
API-036硬约束检查:人工调用大模型的应用由编码 Agent 参与开发的仓库

MCP 客户端或宿主不信任第三方服务自报的工具注解(只读、破坏性、幂等等);副作用和权限由宿主自己的策略决定

怎么检查:评审宿主的权限策略,确认没有根据第三方注解自动放行写操作
为什么、来源
为什么:注解是服务端自己声明的,恶意或有缺陷的服务可以把删除操作标成只读。

自己提供的 MCP 服务仍应如实标注注解,方便可信的宿主使用。

API-037软指导检查:自动命令行工具

命令行工具提供 --json 模式(标准输出只有一个合法 JSON,诊断信息走标准错误),公开稳定的退出码表,并支持非交互运行

怎么检查:CLI 测试用 jq 解析 --json 输出;在无终端环境下运行,检查不会等待输入
为什么、来源
为什么:脚本、CI 和 Agent 要靠稳定的输出和退出码判断结果;混进进度条或提示文字就解析不了。
  • 提供 --no-input,需要确认的操作在非交互时直接失败或要求显式的 --yes。
  • 有修改的命令提供 --dry-run 预览。
  • 流式大列表用单独的模式(如 --output ndjson),不让 --json 时而输出一个对象、时而输出多行。
  • 退出码不直接用 HTTP 状态码;错误输出里带接口错误的 code。
  • 命令结构全局一致,如「产品 名词 动词」。

选型

类别默认备选(何时用)不推荐
接口风格REST + OpenAPI
普通 HTTP 接口,尤其是公开接口和第三方调用
GraphQL(前端频繁自由组合查询,且能做查询复杂度限制)
Connect / gRPC(内部服务间强类型调用或需要流式;Connect 兼容浏览器和普通 HTTP 客户端)
WebSocket(真正的双向实时交互)
为少数页面引入 GraphQL 服务:运维和安全治理成本超过收益
强制浏览器和第三方用原生 gRPC:浏览器不直接支持,接入成本高
OpenAPI 规范版本OpenAPI 3.1 · 规范为 Apache-2.0
OpenAPI 3.2(确实需要 QUERY 方法、流式媒体描述等新特性,且工具链已验证支持)
Swagger 2.0 / OpenAPI 3.0 用于新项目:不完全兼容 JSON Schema,新工具逐步以 3.1 为基线
契约 lintSpectral(规则集放在仓库里) · Spectral 为 Apache-2.0;Redocly CLI 为 MIT(均待核实)
Redocly CLI(需要多文件契约打包(bundle)或想用它的内置规则;可与 Spectral 并用,打包后再 lint)
只看文档预览判断契约对不对:预览能渲染不代表契约正确
破坏性变更检测oasdiff · Apache-2.0(待核实)
openapi-diff(已在用且能满足检测需求时)
对契约文件做纯文本 diff:看不出语义上的破坏
接口文档站Scalar 或 Redoc,静态构建后自托管 · 均为 MIT(待核实)—
私有化项目的文档站引用外部 CDN、字体或在线 schema:内网打不开
客户端与 SDK 生成按语言选专用生成器(见 10–14) · OpenAPI Generator 为 Apache-2.0(待核实)
OpenAPI Generator(需要一次生成多种语言的 SDK;先验证目标语言生成器对 3.1 的支持)
生成的代码手改:下次生成就被覆盖
把错误恢复、缓存、重连、幂等键管理也交给生成器:这些需要手写薄封装并测试
错误格式RFC 9457 Problem Details
迁移期适配旧格式(已有调用方依赖旧格式,需设定迁移截止日期)
200 {success: false}:破坏按状态码工作的客户端、网关和重试逻辑
写操作幂等Idempotency-Key + 持久化幂等记录
客户端自定资源 ID + PUT(资源 ID 可以由客户端生成时,天然幂等)
幂等键只放内存缓存:重启和多实例时失效
只比对键、不比对请求体:会把不同请求误当成重复
并发写强 ETag + If-Match
领域版本号 + 比较并更新(非 HTTP 接口或客户端不便处理 ETag)
后写覆盖先写且不提示:静默丢失别人的修改
列表分页不透明游标 + 有上限的 limit + 确定排序
offset 分页(数据少、基本不变,或确实需要跳页)
不分页返回全量:随数据增长拖垮服务
长任务202 + 任务资源(参考 Google AIP-151 的长时操作)—
长时间占着 HTTP 连接等结果:断线无法恢复,易被网关超时
大文件上传分段、可恢复的上传会话;需要与第三方互通时用 tus 协议
multipart/form-data(小文件)
大文件单个请求、失败只能从头传:弱网下几乎传不完
事件信封与描述CloudEvents 信封 + AsyncAPI 描述事件通道 · CloudEvents、AsyncAPI 规范均为 Apache-2.0
JSON Schema + 文档(事件少、规模小)
每个服务自定事件字段:消费方要逐个适配
用 OpenAPI 描述全部事件语义:表达不了通道、发布订阅关系
对外 webhook 格式与签名Standard Webhooks,用其官方各语言库签名和验签 · 规范为 Apache-2.0
保留已有的格式并行提供(已有大量接收方依赖旧格式)
不签名或自创签名格式:接收方无法用通用库验签,容易出安全漏洞
实时推送SSE + 持久化事件记录 + Last-Event-ID 续传
WebSocket(需要双向交互)
长轮询(中间网络不支持长连接)
只为服务端推送而上 WebSocket:多出连接管理和鉴权复杂度
事件只放进程内存却声称支持续传:重启即丢
MCP 服务端官方 SDK,实现当前正式协议版本
同时兼容旧的握手式版本(仍有旧客户端,需逐版本测试)
手写协议拼装:版本协商、传输和授权细节多,易出错
把所有 REST 接口自动转成 MCP 工具:工具数量爆炸,模型容易误操作
命令行机器输出按 CLI Guidelines(clig.dev)设计,--json 输出配 JSON Schema—
JSON 模式里混入进度条、颜色或提示:无法解析
接口风格
REST + OpenAPI
备选:GraphQL(前端频繁自由组合查询,且能做查询复杂度限制);Connect / gRPC(内部服务间强类型调用或需要流式;Connect 兼容浏览器和普通 HTTP 客户端);WebSocket(真正的双向实时交互)
不推荐:为少数页面引入 GraphQL 服务;强制浏览器和第三方用原生 gRPC
OpenAPI 规范版本
OpenAPI 3.1 · 规范为 Apache-2.0
备选:OpenAPI 3.2(确实需要 QUERY 方法、流式媒体描述等新特性,且工具链已验证支持)
不推荐:Swagger 2.0 / OpenAPI 3.0 用于新项目
契约 lint
Spectral(规则集放在仓库里) · Spectral 为 Apache-2.0;Redocly CLI 为 MIT(均待核实)
备选:Redocly CLI(需要多文件契约打包(bundle)或想用它的内置规则;可与 Spectral 并用,打包后再 lint)
不推荐:只看文档预览判断契约对不对
破坏性变更检测
oasdiff · Apache-2.0(待核实)
备选:openapi-diff(已在用且能满足检测需求时)
不推荐:对契约文件做纯文本 diff
接口文档站
Scalar 或 Redoc,静态构建后自托管 · 均为 MIT(待核实)
不推荐:私有化项目的文档站引用外部 CDN、字体或在线 schema
客户端与 SDK 生成
按语言选专用生成器(见 10–14) · OpenAPI Generator 为 Apache-2.0(待核实)
备选:OpenAPI Generator(需要一次生成多种语言的 SDK;先验证目标语言生成器对 3.1 的支持)
不推荐:生成的代码手改;把错误恢复、缓存、重连、幂等键管理也交给生成器
错误格式
RFC 9457 Problem Details
备选:迁移期适配旧格式(已有调用方依赖旧格式,需设定迁移截止日期)
不推荐:200 {success: false}
写操作幂等
Idempotency-Key + 持久化幂等记录
备选:客户端自定资源 ID + PUT(资源 ID 可以由客户端生成时,天然幂等)
不推荐:幂等键只放内存缓存;只比对键、不比对请求体
并发写
强 ETag + If-Match
备选:领域版本号 + 比较并更新(非 HTTP 接口或客户端不便处理 ETag)
不推荐:后写覆盖先写且不提示
列表分页
不透明游标 + 有上限的 limit + 确定排序
备选:offset 分页(数据少、基本不变,或确实需要跳页)
不推荐:不分页返回全量
长任务
202 + 任务资源(参考 Google AIP-151 的长时操作)
不推荐:长时间占着 HTTP 连接等结果
大文件上传
分段、可恢复的上传会话;需要与第三方互通时用 tus 协议
备选:multipart/form-data(小文件)
不推荐:大文件单个请求、失败只能从头传
事件信封与描述
CloudEvents 信封 + AsyncAPI 描述事件通道 · CloudEvents、AsyncAPI 规范均为 Apache-2.0
备选:JSON Schema + 文档(事件少、规模小)
不推荐:每个服务自定事件字段;用 OpenAPI 描述全部事件语义
对外 webhook 格式与签名
Standard Webhooks,用其官方各语言库签名和验签 · 规范为 Apache-2.0
备选:保留已有的格式并行提供(已有大量接收方依赖旧格式)
不推荐:不签名或自创签名格式
实时推送
SSE + 持久化事件记录 + Last-Event-ID 续传
备选:WebSocket(需要双向交互);长轮询(中间网络不支持长连接)
不推荐:只为服务端推送而上 WebSocket;事件只放进程内存却声称支持续传
MCP 服务端
官方 SDK,实现当前正式协议版本
备选:同时兼容旧的握手式版本(仍有旧客户端,需逐版本测试)
不推荐:手写协议拼装;把所有 REST 接口自动转成 MCP 工具
命令行机器输出
按 CLI Guidelines(clig.dev)设计,--json 输出配 JSON Schema
不推荐:JSON 模式里混入进度条、颜色或提示
  • 契约 lint:两者都是 CI 里独立运行的工具,不随产品分发。
  • 破坏性变更检测:只能发现契约层的破坏,行为层的变化仍需人工评审和契约测试(见 04)。
  • 接口文档站:这里只管接口参考文档;通用文档站见 05。
  • 事件信封与描述:AsyncAPI 文档本身不提供可靠投递、重放和顺序,这些要自己实现。
  • MCP 服务端:各 SDK 的许可证和对当前版本的支持情况,采用时到其仓库核实。

常见错误

错误做法:失败时返回 200 加 {success: false}
应该:用正确的状态码和 RFC 9457 错误体
错误做法:客户端靠匹配错误的 detail 文本判断原因
应该:按 type 或 code 判断
错误做法:只用缓存里 24 小时的幂等键保证付款只执行一次
应该:幂等记录持久化 + 业务唯一约束 + 事务
错误做法:前端回传了 ETag,服务端却先查再无条件更新
应该:用带版本条件的原子更新
错误做法:事件每次重发都换一个 id
应该:重发保持同一个 (source, id)
错误做法:默认承诺事件全局有序、恰好一次
应该:按聚合对象排序 + 至少一次 + 消费方去重
错误做法:验签前先把 JSON 解析再序列化
应该:用原始请求体字节验签
错误做法:用户填什么回调地址就往哪发
应该:校验地址并限制重定向,防 SSRF
错误做法:在快速变化的大表上用页码 + offset 翻页
应该:游标分页 + 确定排序
错误做法:把 llms.txt 当成接口契约或授权依据
应该:契约以 OpenAPI、AsyncAPI、JSON Schema 和测试为准
错误做法:网页表单、HTTP、MCP、CLI 各写一套业务规则
应该:共用一套领域逻辑和授权,各出口单独定契约

待确认

下面的内容还没核实或待补调研,不要当成规则执行。

  • Spectral、Redocly CLI、oasdiff、Scalar、Redoc、OpenAPI Generator、AsyncAPI CLI 的许可证本次未联网核实,以各仓库 LICENSE 为准
  • MCP 2026-07-28 版工具规范中 isError、structuredContent、outputSchema 可为任意 JSON 类型、工具注解不可信等细节本次未逐条联网复核
  • 原报告称 HTTP QUERY 方法已于 2026-06 成为 RFC 10008,未核实;核实前不把 QUERY 写进规则
  • 新接口 JSON 字段默认 camelCase 是本主题的裁决(依据 Microsoft 指南和前端生态),Zalando 等指南用 snake_case;需与 02 再确认口径
  • 待补调研:模拟服务器(mock server)和消费者驱动契约测试工具的选型(与 04 协调)
  • 待补调研:webhook 发送端的现成库或服务(含可私有化部署的方案)
  • 待补调研:Connect、GraphQL 各语言实现与许可证;字段选择与过滤参数的业界约定

来源

  1. S01 OpenAPI Specification(版本索引) · OpenAPI Initiative · 标准 · 核实于 2026-11-14
  2. S02 Announcing OpenAPI v3.2 · OpenAPI Initiative · 官方文档 · 2025-09-23 · 核实于 2026-11-13
  3. S03 RFC 9457: Problem Details for HTTP APIs · IETF · 标准 · 2023-07 · 核实于 2026-11-14
  4. S04 The Idempotency-Key HTTP Header Field(Internet-Draft) · IETF httpapi WG · 标准 · 2026-10-22 · 核实于 2026-11-14
  5. S05 RFC 9110: HTTP Semantics · IETF · 标准 · 2022-06 · 核实于 2026-11-13
  6. S06 Zalando RESTful API Guidelines · Zalando · 社区 · 核实于 2026-11-13
  7. S07 AIP-151: Long-running operations · Google · 社区 · 核实于 2026-11-13
  8. S08 AIP-121: Resource-oriented design · Google · 社区 · 核实于 2026-11-13
  9. S09 GitHub REST API: API versions · GitHub · 案例 · 核实于 2026-11-13
  10. S10 RFC 9745: The Deprecation HTTP Response Header Field · IETF · 标准 · 2025-03 · 核实于 2026-11-13
  11. S11 RFC 8594: The Sunset HTTP Header Field · IETF · 标准 · 2019-05 · 核实于 2026-11-13
  12. S12 CloudEvents Specification · CNCF · 标准 · 核实于 2026-11-13
  13. S13 AsyncAPI Specification · AsyncAPI Initiative · 标准 · 核实于 2026-11-13
  14. S14 Standard Webhooks Specification · Standard Webhooks · 标准 · 核实于 2026-11-14
  15. S15 MDN: Using server-sent events · MDN · 官方文档 · 核实于 2026-11-13
  16. S16 MCP Specification: Tools · Model Context Protocol · 标准 · 2026-07-28 · 核实于 2026-11-13
  17. S17 MCP Specification: Versioning · Model Context Protocol · 标准 · 核实于 2026-11-14
  18. S18 MCP Specification: Authorization · Model Context Protocol · 标准 · 2026-07-28 · 核实于 2026-11-14
  19. S19 Command Line Interface Guidelines · clig.dev · 社区 · 核实于 2026-11-13
  20. S20 Spectral · Stoplight · 官方文档 · 核实于 2026-11-13
  21. S21 Redocly CLI · Redocly · 官方文档 · 核实于 2026-11-13
  22. S22 oasdiff · oasdiff · 官方文档 · 核实于 2026-11-13
  23. S23 Scalar · Scalar · 官方文档 · 核实于 2026-11-13
  24. S24 OpenAPI Generator · OpenAPI Tools · 官方文档 · 核实于 2026-11-13
  25. S25 tus: Resumable upload protocol · tus · 社区 · 核实于 2026-11-13
  26. S26 GraphQL: Learn · GraphQL Foundation · 官方文档 · 核实于 2026-11-13
  27. S27 Connect: Introduction · Connect · 官方文档 · 核实于 2026-11-13
  28. S28 Microsoft Azure REST API Guidelines · Microsoft · 案例 · 核实于 2026-11-13