RESTful API设计:那些年我们一起踩过的坑,今天一次说清楚

2026-04-05 8 0

RESTful API设计:那些年我们一起踩过的坑,今天一次说清楚

干这行这么多年,我见过太多团队在API设计上翻车。有的返回格式乱成一锅粥,有的一致性差到让人怀疑人生,还有的接口文档写得跟悬疑小说似的——看到最后也不知道这破接口到底咋用。

今天不整虚的,就把RESTful API设计中最常见的坑拉出来遛遛,顺便给出我的避坑指南。纯属实战经验,拿去即用。


一、URL设计:你的路径是给人看还是给机器看?

先来看一个反面教材:

GET /getUserInfo?userId=123
POST /modifyData
GET /queryAllProductInfo

看到这种接口,我内心是崩溃的。这哪里是RESTful,这分明是在写口语化描述。

RESTful的核心是资源导向。URL应该是名词,不是动词。动词应该体现在HTTP方法里。

正确姿势:

GET /users/123          # 获取用户
PUT /users/123           # 更新用户
DELETE /users/123        # 删除用户
GET /users/123/orders    # 获取用户的订单列表

记住一个原则:URL是地址,不是命令。你说"去超市买牛奶"不能说成"去买东西用钱换牛奶的超市在东边那个路口",对吧?一样的道理。


二、状态码:别总返回200然后在body里说"失败了"

这个坑我见过无数次了:

HTTP/1.1 200 OK
{
  "code": 500,
  "message": "服务器内部错误"
}

兄弟,你这是跟我玩狼人杀呢?HTTP状态码是给调用方判断用的,你返回200但body里说失败,调用方得先解析body才能知道出事了——这完全违背了HTTP状态码的设计初衷。

标准做法:

200 OK        # 成功
201 Created   # 创建成功(POST/PUT返回)
204 No Content # 删除成功,无返回body
400 Bad Request # 参数错误
401 Unauthorized # 未认证
403 Forbidden   # 无权限
404 Not Found    # 资源不存在
500 Internal Server Error # 服务器错误

有人会说:"有些业务错误码需要细粒度控制,比如'余额不足'和'转账限额超限'都是400,调用方没法区分。"

好问题。解决方案是在body里放业务错误码,但HTTP状态码要先对

HTTP/1.1 400 Bad Request
{
  "code": "INSUFFICIENT_BALANCE",
  "message": "余额不足",
  "detail": {
    "currentBalance": 50.00,
    "requiredAmount": 150.00
  }
}

状态码负责大类,body里的code负责细分。各司其职,清晰明了。


三、分页:要么不做,要么做完整

很多API的分页实现堪称行为艺术:

// 方案A:只有数据,没有分页信息
{
  "users": [...]
}

// 方案B:返回总数,但没告诉用户怎么用
{
  "users": [...],
  "total": 12345
}

// 方案C:假装分页
{
  "users": [...],  // 其实一次返回了全部
  "page": 1
}

正确的分页应该包含:当前页、每页条数、总数、是否有下一页

{
  "data": [...],
  "pagination": {
    "page": 2,
    "pageSize": 20,
    "total": 158,
    "totalPages": 8,
    "hasNext": true,
    "hasPrev": true
  }
}

还有个关键点:游标分页 vs 偏移分页。数据量小用偏移分页,简单直观;数据量大或者需要实时性,用游标分页(基于ID或时间戳),避免深分页性能问题。


四、版本管理:没有版本控制的API是在耍流氓

我见过最离谱的版本管理是——没版本。接口直接改,客户端直接崩。

版本控制的三种主流方式:

// 方式1:URL路径(最常见)
GET /v1/users/123
GET /v2/users/123

// 方式2:Header(更"优雅"但不便调试)
GET /users/123
API-Version: 2023-01-01

// 方式3:Query参数(不推荐)
GET /users/123?version=2

我的建议是用URL路径。理由:直观、可测试、可追踪、出问题排查快。

版本升级的原则:老版本尽量保持时间长一点,给调用方足够的迁移时间。别像某些大厂一样,接口说下线就下线,一点情面不讲。


五、接口文档:写得烂的文档比没文档更可怕

很多团队觉得有Swagger/OpenAPI就算有文档了。太天真了。

一份合格的API文档必须包含:

  • 请求示例和响应示例(真实的,不是placeholder)
  • 每个字段的类型、含义、是否必填
  • 错误码说明(不只是code,还要有解决方案)
  • 业务场景描述(这个接口是干啥的,什么时候用)
  • 认证方式(OAuth2? API Key? JWT?)

我推荐Knife4j(Java系)或者Swagger UI,配合Apifox做团队协作。工具是其次,关键是内容。


六、安全:基础不做好,后面全是泪

这块很多人觉得是老生常谈,但我见过太多生产环境的翻车:

  • 接口没鉴权,数据裸奔
  • 敏感信息(密码、token)直接放URL里,被日志全暴露
  • 没做请求限流,被人一顿狂刷服务器就炸了

基础安全三件套:

1. HTTPS必须(别省那个证书钱)
2. 认证鉴权必须(JWT/OAuth2/签名)
3. 参数校验必须(前后端都要做,后端不能信前端)
4. 限流熔断必须有(防止DDoS和系统过载)

还有个小细节:错误信息不要暴露内部细节。比如"密码错误"和"用户不存在"要统一返回"用户名或密码错误",不然你就在帮黑客缩小攻击范围。


写在最后

API设计看起来是技术活,其实本质是产品思维——你的接口是给别人用的,要站在调用方的角度思考。

好的API设计有这么几个特点:

  • 自解释:看URL就知道干啥
  • 一致性:风格统一,减少学习成本
  • 容错性:输入不规范也能优雅处理
  • 可追踪:日志、监控、告警齐全

如果你接手一个烂摊子API,别急着重构。先画个架构图,理清依赖关系,然后小步快跑,逐步演进。一口气推倒重来的结果通常是一起重来。

有问题评论区见,我尽量回。觉得有用的,点个在看,我们下篇见。

相关文章

「懒人福音」AI工具一键部署,自己折腾还是花钱搞定?
你的数据库事务可能是定时炸弹:没人告诉你的隔离级别真相
RESTful API 已经不是银弹了,你们还在盲目追从?
你的SQL正在被你的”优化”悄悄杀死
数据库慢得像蜗牛?别急着加索引,先搞清楚这8个隐形杀手
你的代码太优雅了,以至于跑不动

发布评论