JSON、表单与图片接口的响应设计规范
文章给出 JSON、表单、图片三类接口的响应设计约定:JSON 用统一四字段信封与稳定错误码,表单按 Accept 做内容协商并返回字段级错误,图片默认返回二进制、需要元数据时切 JSON,并统一携带 request_id 便于追踪。
- JSON 接口统一四字段信封,成功与失败走同一条解析路径
- 业务码表达具体原因,HTTP 状态码表达语义层结果,不可混用
- data 类型恒定,空列表返回 [],ID 用字符串避免精度丢失
- 表单接口按 Accept 做内容协商,校验失败返回 422 与字段级 errors
- 图片接口默认返回二进制,需要元数据时切 JSON,出错绝不返回 200
引言:响应结构是最容易被 AI 写坏的部分#
这两年接口开发的门槛在快速下降:脚手架、序列化、参数校验、甚至整套 Controller 都能被工具一次性生成。但生成得越快,越容易暴露一个问题——大家写的是能跑的代码,而不是稳定的契约。同一个服务里,有的接口成功时返回对象、失败时返回字符串;有的图片接口出错时返回一段 HTML 报错页;有的表单接口把校验错误塞进 302 跳转的 query 里。这些细节不会让单测失败,却会让调用方(无论是人还是自动化客户端)付出成倍的适配成本。
本文以 API.PLUS 上常见的三类接口形态——JSON 数据接口、表单提交接口、图片二进制接口——为线索,给出一套可以直接抄进团队规范里的响应设计约定。核心目标只有一个:让响应在任何分支下都是可预测、可机读、可降级的。
一、先立契约,再写实现#
响应设计不是编码完成后的收尾工作,它应该和接口路径一起被确定下来。建议在动手前先回答四个问题:
- 成功与失败是否共用同一个外层结构?如果不共用,客户端就要写两套解析逻辑。
- 错误信息是给人看的,还是给程序判断的?两者必须同时存在,缺一不可。
- 同一字段的类型是否永远不变?今天返回数组、明天返回 null,是联调事故的高发区。
- 出问题时能不能只靠一个 ID 定位到日志?没有 request_id,线上排查基本靠猜。
把这四条写进接口文档,比写十页使用说明更有价值。API.PLUS 的接口文档在这一点上做得比较克制,例如 IP 查询接口 与 POST 示例接口,参数、返回、错误示例都在同一页内,便于调用方一次性对齐预期。
二、JSON 接口:统一信封 + 稳定错误码#
JSON 是最容易被设计得五花八门的格式。推荐使用固定四字段信封,让成功与失败走同一条解析路径:
示例说明:以下代码仅用于逻辑验证,生产环境需补充异常处理、超时与重试、日志与监控告警及降级策略。
{
"code": 0,
"message": "ok",
"request_id": "req_9f1c2a7b",
"data": {
"ip": "8.8.8.8",
"country": "United States",
"isp": "Google LLC"
}
}
失败时只改变 code、message 与 data 的取值,字段本身永远存在:
{
"code": 40001,
"message": "invalid parameter: ip",
"request_id": "req_9f1c2a7b",
"data": null
}
几个容易踩坑的地方值得单独强调:
- 业务码与 HTTP 状态码分工明确。HTTP 状态码表达传输层与语义层结果(200 / 400 / 401 / 429 / 500),业务码表达具体原因。不要用
200 + code=500糊弄监控系统。 - data 的类型必须恒定。列表为空时返回
[]而不是null;单对象缺失时返回null而不是{}。类型抖动比字段缺失更难处理。 - ID 一律用字符串。超过 2^53 的整数在前端会被静默截断,这类 bug 极难复现。
- 时间统一 ISO 8601 并带时区,例如
2026-10-28T09:30:00+08:00,不要返回时间戳与格式化字符串混用。 - 布尔值不要用 0/1。不同语言的弱类型转换行为不一致,前端
if ("0")永远为真。
调用一个返回 JSON 的接口时,可以顺手用 Accept 头声明期望格式,多数实现会据此选择序列化方式:
curl -s -H "Accept: application/json" \
"https://www.api.plus/api/get?apikey=YOUR_KEY&ip=8.8.8.8"
注意 apikey 属于凭证,不应出现在前端日志、错误上报或截图里。生产环境建议由服务端代理调用,前端只拿到必要字段。
三、表单接口:内容协商与字段级错误#
表单接口(application/x-www-form-urlencoded 与 multipart/form-data)长期存在一个误区:因为浏览器默认会渲染 HTML,所以错误也用 HTML 表达。这在 2026 年已经不太成立——调用表单接口的往往不是浏览器表单,而是移动端、脚本或工作流编排工具。
推荐的处理方式是按 Accept 分流:
Accept: application/json时,无论成功失败都返回 JSON 信封,字段错误放进data.errors数组,每项包含field与reason。- 浏览器直连时返回 HTML 页面,但要使用正确的语义状态码(校验失败 422,未登录 401),而不是一律 200。
- 不要把错误信息拼进 302 的 Location,重定向会丢失请求体上下文,日志里只剩下一串 URL。
{
"code": 42201,
"message": "validation failed",
"request_id": "req_5b8e1d40",
"data": {
"errors": [
{ "field": "email", "reason": "invalid format" },
{ "field": "name", "reason": "required" }
]
}
}
另外两点经常被忽略:其一,涉及写操作的表单接口应当具备幂等语义,重复提交不能产生多条记录,可用客户端传入的幂等键配合唯一索引兜底;其二,文件上传字段要与普通字段分开限制大小,超限时返回明确的 413 而非连接被重置。具体字段约定可参照 POST 示例接口文档 的说明。
四、图片接口:字节流与元数据的双通道#
图片接口的特殊性在于它有两种合理的返回形态,混用就会出问题。业界比较通行的做法是默认返回二进制,需要元数据时显式切换:
- 默认响应头为
Content-Type: image/jpeg(或实际格式),响应体即图片字节,便于<img>直接引用。 - 通过
type=json之类的参数或Accept: application/json切换为 JSON 信封,返回图片 URL、尺寸、格式、过期时间等元数据。
API.PLUS 的 随机动漫壁纸接口 就提供了这种切换能力,例如:
# 直接拿二进制图片
curl -s -o wallpaper.jpg "https://www.api.plus/api/dongman"
# 拿 JSON 元数据,便于前端做预加载与占位图
curl -s "https://www.api.plus/api/dongman?type=json"
图片接口最容易犯的三个错误:
- 出错时返回 200 + HTML。浏览器会把错误页当成图片缓存下来,用户看到的是持续破图。图片通道出错必须返回非 200 状态码,且响应体为纯文本或 JSON。
- 缺少缓存头。随机图片可以标记
Cache-Control: no-store,固定资源则应给出max-age与ETag,并正确响应If-None-Match返回 304。 - 不返回 Content-Length。缺少长度信息会让部分客户端无法展示进度条,也会影响反向代理的缓冲策略。
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 284613
Cache-Control: no-store
ETag: "dm-7c31a9"
X-Request-Id: req_2d6f8b11
如果业务确实需要用 JSON 传图片内容,优先返回可访问的 URL 而不是 base64。base64 会让体积膨胀约 33%,并且无法享受浏览器与 CDN(Content Delivery Network,内容分发网络) 的图片缓存。
五、可观测性:让每个响应都能被追查#
响应规范的最后一块拼图是追踪能力。建议在所有形态的响应中都带上 X-Request-Id 响应头(JSON 接口同时在体内回传 request_id),并在服务端日志中以该 ID 为主键串联上下游调用。这样用户报障时只需提供一个 ID,就能定位到具体参数、耗时与后端依赖状态。
错误码也需要一份可维护的登记表,避免相邻模块各自编号导致语义冲突:
| 业务码 | HTTP 状态 | 含义 | 客户端建议动作 |
|---|---|---|---|
| 0 | 200 | 成功 | 正常解析 data |
| 40001 | 400 | 参数缺失或格式错误 | 修正参数后重试 |
| 40101 | 401 | API Key 无效或缺失 | 检查凭证,不要重试 |
| 42901 | 429 | 触发限流 | 按 Retry-After 退避 |
| 50001 | 500 | 服务端内部错误 | 携带 request_id 反馈 |
限流响应的 Retry-After 头尤其值得实现,它能让客户端从“盲目重试”变成“有节奏重试”,显著降低雪崩风险。相关的设计思路可以在 API 文章中心 找到更完整的讨论。
六、落地检查清单与总结#
把上面的约定压缩成一份评审清单,新接口上线前逐条打勾即可:
- 成功与失败共用同一外层信封,字段始终存在,
data类型恒定; - 业务码与 HTTP 状态码各自表达不同层次的信息,错误码有登记表;
- 所有响应携带
X-Request-Id,服务端日志可按其检索; - 表单接口按
Accept做内容协商,校验失败返回 422 与字段级错误; - 图片接口默认返回二进制并设置正确的
Content-Type、Content-Length与缓存头,出错时绝不返回 200; - 限流返回 429 并附带
Retry-After。
总结一下:在代码可以被大量自动生成的今天,接口的价值越来越集中在“契约是否稳定”上。JSON 接口靠统一信封与稳定错误码取胜,表单接口靠内容协商与字段级错误取胜,图片接口靠二进制与元数据的清晰分离取胜。三者共同的前提是——响应结构先于实现被定义,并且在所有分支下保持一致。
想快速验证这套规范,可以直接在 API.PLUS 注册账号获取免费 API Key,用 IP 归属地查询接口 观察标准 JSON 响应,用 随机动漫壁纸接口文档 体会二进制与 JSON 两种返回形态,再结合 POST 请求示例接口 对齐表单约定。遇到具体的字段或状态码疑问,可通过 技术支持 反馈。