背景:本文以一份 1931 行的"安全生产类平台"接口规范为蓝本——它包含登录、重大危险源监测设备、双预防(安全风险分析单元/事件/管控措施/隐患排查任务/记录/信息)、特殊作业票、教育培训等 30+ 个端点,全部采用统一响应体 + Bearer Token +
add/update/delete三段式风格。本文重点不是"再写一遍规范",而是抽丝剥茧出企业级 REST API 设计的 6 大原则,让读者下次写接口时直接对号入座。Why 2020 年:REST 在 2014-2018 完成主流化(Spring 5 / JAX-RS 2.1 / OpenAPI 3.0 都是这一时期定型的),2020 年是企业从"能跑"转向"规范 + 可观测"的分水岭。本文的方法论至今仍是企业级接口设计的底座。
一、统一响应体:把"成功"和"业务失败"分开
很多团队在写 REST 接口时,第一反应是"成功返回数据、失败抛 4xx/5xx + 异常 message"——但企业级 API 必须把"协议层错误"和"业务层错误"分开,否则前端要写两套解析逻辑,后端监控也要维护两套指标。
1.1 业界三大响应体风格对比
| 风格 | 成功 | 业务失败 | 网络失败 | 典型代表 |
|---|---|---|---|---|
| HTTP 优先 | 200 + 数据 | 4xx/5xx + 错误体 | 5xx + 异常 | Spring MVC 默认、Express 默认 |
| 统一信封 | 200 + {code:0, data} | 200 + {code:1xxx, msg} | 5xx + 异常 | 阿里云 API、字节内部 RPC 协议 |
| 混合模式 | 200/201 + 数据 | 4xx + 业务 code | 5xx + 异常 | GitHub API、Stripe API |
这份规范采用"统一信封"风格,所有业务成功都返回 200,靠 code 字段区分:
| |
设计要点:
code = 0表示业务成功,非 0 表示业务错误(避免误用 HTTP 200 + 业务失败 + HTTP 4xx 三者交叉)success冗余但友好,前端if (res.success)比if (res.code === 0)可读性高msg用中文(业务系统),对外公开的 API 建议英文 + 国际化 keydata类型根据业务而定,列表/对象/null 都允许
1.2 状态码语义对照表
| HTTP 状态码 | 业务场景 | 后端处理 | 前端处理 |
|---|---|---|---|
| 200 | 业务成功(包含 code != 0 业务失败) | 永远返回 200 | 看 success 字段 |
| 400 | 请求参数格式错误(JSON 解析失败) | Spring @Valid 触发 | 弹"参数错误"Toast |
| 401 | Token 缺失/过期/无效 | 拦截器抛 AuthException | 跳登录页 |
| 403 | 权限不足 | RBAC 拦截 | 弹"无权限" |
| 404 | 资源不存在 | @ExceptionHandler | 弹"记录不存在" |
| 429 | 限流 | Sentinel/Sentinel 拦截 | 弹"操作太频繁" |
| 500 | 系统异常 | 全局异常处理 | 弹"系统异常"+ 上报埋点 |
| 502/503/504 | 网关/上游异常 | Nginx/OpenResty | 弹"服务暂不可用" |
二、URL 命名:模块化 + 资源化 + 动词三段式
这份规范的 URL 设计非常典型:
| |
2.1 URL 设计的 4 层语义
| 层级 | 含义 | 这份规范的做法 |
|---|---|---|
| L1 一级模块 | 业务域 | hazard(重大危险源)、prevent(双预防 + 特殊作业票 + 教育培训)、system(系统) |
| L2 二级模块 | 子系统 | monitorEquip(监测设备)、riskUnit(风险单元) |
| L3 动作 | CRUD | add / update / delete(不是 RESTful 的 POST/GET/PUT/DELETE) |
| L4 路径参数 | 资源 ID | 写在请求体 id 字段,不是 URL |
2.2 这种"动作式 URL" vs RESTful 风格
RESTful 风格(HTTP 动词 + 资源):
| |
这份规范的动作式风格:
| |
| 维度 | RESTful | 动作式(这份规范) |
|---|---|---|
| HTTP 动词丰富度 | 4-5 个 | 仅 POST(与 CSRF/中间件兼容性好) |
| 网关路由匹配 | 复杂(要看动词) | 简单(只看路径) |
| 审计日志 | 看 method + path | 看 path(更易聚合) |
| 团队学习成本 | 中 | 低(无歧义) |
| 幂等性 | 需显式声明 | update/delete 天然要求幂等 |
| OpenAPI 自动生成 | 友好 | 不友好(同一路径下多个动作) |
我的建议:对内系统、CRUD 密集型、强审计 → 动作式(
add/update/delete);对外 API、平台化 → RESTful。这份规范属于前者,理由是它要对接大量前端 + 移动端 + 第三方园区版系统,用POST /xxx/add这种风格,后端可以用统一的请求体 + 鉴权 + 日志拦截器,避免 HTTP 动词带来的中间件兼容性问题。
2.3 命名规范:驼峰 vs 短横线
| |
| 风格 | 优点 | 缺点 |
|---|---|---|
驼峰 monitorEquip | 与 Java/Go 字段名一致 | URL 编码 %2D 不需要,但 RFC 3986 不推荐 |
短横线 monitor-equip | RFC 3986 友好、SEO 友好 | 需与字段名手动映射 |
最佳实践:对外 API 用短横线(GitHub、Twitter、Stripe 都这样),对内 RPC 用驼峰(与业务代码一致,减少转换)。
三、鉴权:Bearer Token + 30 天有效期
3.1 登录接口
| |
请求体:
| |
响应体:
| |
脱敏说明:源文档中
userName默认填admin、password默认填123456、token是一个真实的 UUID 格式字符串(b5b6b03f-18f4-4caf-acdf-25c5cc555bd3)。默认账号密码不应在博文中演示,token 也应视为凭据——博文全部用{{}}占位。
3.2 业务请求的鉴权头
| |
关键设计:
| 项 | 取值 | 原因 |
|---|---|---|
| 鉴权方案 | Bearer Token | RFC 6750 标准,与 OAuth 2.0 / OIDC 兼容 |
| 有效期 | 30 天 | 长效适合企业用户(避免每天重新登录),但配合刷新机制更佳 |
| 存储 | localStorage / sessionStorage | 前端选型决定(localStorage 持久但有 XSS 风险,HttpOnly Cookie 安全但要 CSRF 防护) |
| 传输 | HTTPS 强制 | 防止 token 泄露 |
| 撤销 | 服务端黑名单 + JWT | 推荐:Redis 黑名单 + 短 JWT |
3.3 进阶:刷新令牌模式
| |
返回新的 access_token(短效 2 小时)+ 复用 refresh_token(长效 30 天)。这种"双 token"模式是 OAuth 2.0 推荐的工业实践,避免一个长效 token 泄露就要全员重置。
四、请求/响应体设计:5 个核心要素
4.1 请求体的 5 段式结构
以"重大危险源-监测设备-新增"为例(这份规范最详细的端点):
| 要素 | 字段 | 类型 | 必选 | 备注 |
|---|---|---|---|---|
| 基础标识 | id | string | 是 | 主键 |
| 业务字段 | monitorName monitorCode monitorType numericalUnit rangeMax rangeMin | string | 是 | 业务核心数据 |
| 责任字段 | responsibilityPeopleName deptName | string | 是 | 责任人/部门 |
| 位置字段 | longitude latitude address | number/string | 是 | 经纬度 + 地址 |
| 设备字段 | manufacturer checkTime checkCycle | string/datetime | 是 | 厂家/校验 |
| 告警字段 | oneLevelHigh twoLevelHigh oneLevelLow twoLevelLow | string | 是 | 一二级高低报 |
| 类型字段 | monitorSpotType state equipmentType equipmentName | string | 是 | 类型/状态 |
4.2 字段类型选型决策树
| |
关键提醒:永远不要用 number 表示 ID/编号/金额!JavaScript 的
Number是双精度浮点,Number.MAX_SAFE_INTEGER是9007199254740991(约 9 * 10^15),超出后12345678901234567 === 12345678901234568会返回true。雪花 ID 通常是 18-19 位,必须用 string。
4.3 必选/可选字段的标注规范
| |
4.4 错误响应体的差异化
| |
code 设计原则:
- 0 = 成功
- 1xxx = 业务错误(参数错误、唯一冲突、状态非法等)
- 2xxx = 鉴权错误(token 过期、权限不足)
- 3xxx = 第三方错误(短信/邮件/支付失败)
- 4xxx-5xxx = 内部错误(数据库异常、Redis 异常等)
- -1 = 系统兜底
五、批量与同步:园区版双向同步的 4 种模式
这份规范有一个特殊设计:几乎所有端点的接口功能都写"企业版新增数据时同步到园区版"——这意味着每个写操作都是双写的。这种"企业版 + 园区版"的同步模式在政企/工业互联网场景非常典型。
5.1 4 种同步模式对比
| 模式 | 实时性 | 复杂度 | 一致性 | 适用 |
|---|---|---|---|---|
| 同步双写 | 实时 | 低 | 强 | 企业版 ↔ 园区版(这份规范的做法) |
| 异步消息 | 准实时(秒级) | 中 | 最终一致 | 跨地域多活、削峰填谷 |
| CDC 监听 | 准实时 | 高 | 最终一致 | 数据库迁移、异构同步 |
| 定时拉取 | 延迟(分钟/小时) | 低 | 弱 | 对账、非关键数据 |
5.2 同步双写的实现细节
| |
5 个关键决策:
- 是否同步等待园区版响应? 答:否,园区版失败不阻断企业版(否则企业用户卡死)
- 失败后如何重试? 答:MQ 异步重试 + 死信队列人工介入
- 如何避免重复同步? 答:每个端点都带
id(主键),园区版用 upsert 语义- 如何追踪同步状态? 答:每个对象加
sync_status(待同步/已同步/失败)+sync_time- 如何保证最终一致? 答:定时对账任务(每天凌晨拉取企业版增量 vs 园区版已收,对账差异)
5.3 批量同步的端点设计
| |
| |
批量端点的 3 个原则:
- 总量限制:单次 ≤ 500 条(超过容易超时/内存溢出)
- 部分成功语义:返回
data.succeeded/data.failed两个数组- 失败明细可重试:
failed[].reason标明原因,前端可一键重试
六、CRUD 三段式 vs RESTful 的 7 大差异
| 维度 | 动作式(这份规范) | RESTful | 推荐 |
|---|---|---|---|
| 新增 | POST /xxx/add | POST /xxx | 等价 |
| 修改(整对象) | POST /xxx/update | PUT /xxx/{id} | 等价 |
| 修改(部分字段) | POST /xxx/update | PATCH /xxx/{id} | RESTful 更精确 |
| 删除 | POST /xxx/delete | DELETE /xxx/{id} | 等价 |
| 查询单个 | POST /xxx/getById | GET /xxx/{id} | RESTful 天然缓存 |
| 查询列表 | POST /xxx/list | GET /xxx?page=1&size=20 | RESTful 更标准 |
| 查询复杂条件 | POST /xxx/search | POST /xxx/search | 等价(因为 GET 装不下复杂 JSON) |
实战选型:
- CRUD 增删改 → 动作式(少一层 RESTful 心智负担)
- 查询(特别是 GET)→ RESTful(浏览器/网关/CDN 都能缓存)
- 复杂搜索(多条件 + JSON body)→ 动作式(
POST /search不可避免)
七、OpenAPI 3.0 自动化生成
这份规范是手写 Markdown 的,但现代化的企业 API 规范应该从代码生成:
7.1 Java + springdoc-openapi
| |
7.2 自动生成 OpenAPI 3.0 + Swagger UI
| |
访问 http://{{INTERNAL_HOST}}:8080/swagger-ui.html 即可看到自动生成的接口文档。比手写 Markdown 强 10 倍——前后端联调、自动化测试、Mock 数据都能从 OpenAPI 自动派生。
八、6 大设计原则速记
- 统一信封:所有响应都是
{code, msg, data, success},业务成功用 200 - Bearer Token:Authorization 头 + 30 天有效期 + HTTPS 强制
- 模块化 URL:
/一级模块/二级模块/动作,动作可选add/update/delete或 HTTP 动词 - 字段类型谨慎:ID/编号/金额 永远用 string,时间用 ISO 8601
- 批量与同步:单次 ≤ 500 条 + 部分成功 + MQ 异步重试 + 定时对账
- OpenAPI 自动化:从代码注解生成文档,不要手写 Markdown
九、典型代码生成(Java + Spring Boot)
| |
十、参考与延伸
- OpenAPI 3.0 规范:https://swagger.io/specification/
- RFC 6750 - OAuth 2.0 Bearer Token:https://datatracker.ietf.org/doc/html/rfc6750
- RESTful API 设计指南(GitHub):https://docs.github.com/en/rest
- Stripe API 设计:https://stripe.com/docs/api(业界标杆)
- Google API Design Guide:https://cloud.google.com/apis/design
- 微软 REST API 指南:https://github.com/microsoft/api-guidelines
下一步:建议直接用 springdoc-openapi(Java)或 swaggo(Go)从代码生成 API 文档;用 Postman / Apifox 维护接口测试用例;用 YApi / Apifox 做 Mock 数据;用 Pact 做消费者驱动的契约测试。
2024+ 视角
2020 年的"统一响应体 + Bearer Token + RESTful"骨架在 2024-2026 年依然成立,但生态发生了几个关键演进:
- OpenAPI 3.1 落地:3.0 在 2024 年仍是主流,但 3.1 已对齐 JSON Schema 2020-12 规范,并支持 Webhook 和 API 设计优先(spec-first)模式。Stoplight Elements / Redocly 等文档渲染工具成为新标配。
- API 网关与契约测试:
- 网关:Kong 3.x、Apigee、Apache APISIX 3.x(云原生 + eBPF 加速)已成主流
- 契约测试:Pact 2.0 + Pactflow 是消费者驱动测试的工业标准,配合 CI 做兼容性回归
- 鉴权演进:Bearer Token + JWT 仍是基础,但OAuth 2.1(2024 草案)将 PKCE 设为强制;企业级推荐 OIDC(OpenID Connect) + Keycloak / Auth0 / Authing。
- API 安全:OWASP API Security Top 10(2023 版) 把"Broken Object Level Authorization(BOLA)“列为 #1——任何列表/详情接口都要做资源所有权校验。42Crunch / APIsec 提供自动化 API 安全扫描。
- GraphQL / gRPC 互补:
- 复杂前端聚合场景:GraphQL(Hasura、Apollo、Yoga)正在替代"网关聚合多个 REST”
- 内部服务通信:gRPC + protobuf 已成事实标准(Envoy/Istio 内部走 xDS/gRPC)
- 可观测性:API 监控从"看 HTTP 状态码"升级到 RED(Rate/Error/Duration)+ 业务维度 trace。OpenTelemetry 1.x + Jaeger / Tempo 把 traceid 注入 HTTP header,跨服务追踪成为标配。
- 园区版/双写模式进化:2024 年企业级同步更推荐 CDC(Change Data Capture) ——Debezium 监听 MySQL binlog,Kafka 分发,下游订阅。比"应用层 try-catch 同步双写"更可靠、侵入小。
实战建议更新:
- 单体 → REST + OpenAPI + 统一信封
- 微服务 → REST(对外)+ gRPC(对内)+ GraphQL(BFF)
- 鉴权 → OIDC + OAuth 2.1 + RBAC/ABAC
- 文档 → Spec-First(OpenAPI 3.1 + Stoplight)
- 测试 → 契约测试(Pact)+ E2E(Playwright)+ 性能(k6)
- 同步 → 避免应用层双写,改 CDC + 事件驱动
2020 年这篇的"6 大设计原则"骨架完全成立,2024+ 视角主要补全的是 OAuth 2.1、OWASP API Top 10、CDC 同步、OpenTelemetry 四个维度。
