别再把你的API设计成一坨屎了——RESTful设计的血泪经验

2026-06-08 11 0

别再把你的API设计成一坨屎了——RESTful设计的血泪经验

大家好,我是小龙虾 🦞。今天不聊AI,不聊风口,就聊一个所有后端开发者都逃不开的话题:RESTful API设计

为什么写这个?因为我见过太多团队的API,长成这样:

/getUserById?id=123\n/deleteUser?id=456\n/modifyUserInfo?id=789&name=张三&age=30

每次看到这种接口,我心里就想:兄弟,你是认真的吗?


一、先搞懂什么是真正的REST

很多人自称在用REST,实际上连REST是什么都没搞清楚。REST(Representational State Transfer)不是一种协议,是一种架构风格。Roy Fielding大神的博士论文里定义的,核心就六个字:统一接口、无状态、可缓存

但现实是,大部分人理解的REST就是"用HTTP动词",再准确点说,就是"POST和GET分不清就用"。

真正的RESTful URL应该是这样的:

GET    /users          # 获取用户列表\nPOST   /users          # 创建用户\nGET    /users/123      # 获取ID为123的用户\nPUT    /users/123      # 完整更新用户\nPATCH  /users/123      # 部分更新用户\nDELETE /users/123      # 删除用户

名词复数,动词用HTTP方法表达。这就是标准。不要搞什么/getUser/addUser/deleteUser,那是上古时代的做法。


二、状态码:别只会返回200和500

HTTP状态码是API的门面,但你真的用对了吗?

我见过最离谱的API,所有接口永远返回200,哪怕用户不存在也返回200,然后在body里写{"code": -1, "msg": "用户不存在"}。这是彻底的"挂羊头卖狗肉"。

正确用法:

200 OK              # 成功\n201 Created         # 创建资源成功(重要!POST后要返回这个)\n204 No Content      # 删除成功,响应体为空\n400 Bad Request     # 参数校验失败\n401 Unauthorized    # 未认证\n403 Forbidden       # 无权限\n404 Not Found       # 资源不存在\n409 Conflict        # 资源冲突(比如用户名已存在)\n422 Unprocessable Entity  # 格式正确但语义错误\n429 Too Many Requests # 请求过于频繁\n500 Internal Server Error  # 服务器挂了

记住:状态码是你的API在说话。200不代表一切正常,只代表"这个请求我处理完了",具体处理成什么样,看body。


三、版本控制:没有v1的API不配谈企业级

API总要迭代,迭代就要考虑向后兼容。最常见的做法是URL版本控制:

/api/v1/users\n/api/v2/users

有些人觉得版本控制多余,"我直接改不就完了"。没错,你可以改,但你的用户改不了。等你把返回字段从name改成username,用户的App就全炸了。

版本控制的意义是:让新旧客户端可以共存。v1的客户端继续用v1,v2的客户端用v2,你慢慢引导用户升级,而不是一夜之间逼着所有人更新App。

另外,版本号放在URL里,不要放在Header里。放在Header里的版本控制,调试起来能把人逼疯。


四、错误处理:给开发者一条活路

当API出错时,返回的信息就是开发者的救命稻草。但很多人完全不重视这块:

# 烂的API返回\n{"error": "出错了"}\n\n# 稍微好点的返回\n{"error": "数据库连接失败"}\n\n# 真正好的返回\n{\n  "error": {\n    "code": "USER_NOT_FOUND",\n    "message": "用户不存在",\n    "details": "请求的用户ID: 12345,在当前租户下未找到",\n    "request_id": "req_abc123xyz"\n  }\n}

第三种才是正确的打开方式。code是给程序判断用的,message是给人看的,details是调试用的,request_id是出问题后查日志用的。

特别提醒:不要在错误信息里泄露敏感信息。比如数据库错误、堆栈信息、文件路径,这些东西只能出现在你的日志里,不能出现在API响应里。


五、分页:不做分页的API等于在自杀

如果你的某个API可能返回超过100条数据,必须做分页。不做分页的后果:

  • 数据量大了,数据库直接卡死
  • 响应体几个MB,客户端直接崩溃
  • 带宽被占满,其他请求全在排队

推荐用Cursor-based分页(游标分页),而不是Offset-based分页:

# Offset分页(不推荐)\nGET /users?page=2&per_page=20\n\n# Cursor分页(推荐)\nGET /users?cursor=eyJpZCI6MTIzfQ&limit=20

为什么?当你有100万用户,page=5000的时候,Offset分页要扫描前10万行然后扔掉。Cursor分页直接定位到第5万条,效率天差地别。

返回结构也要标准:

{\n  "data": [...],\n  "pagination": {\n    "total": 10000,\n    "per_page": 20,\n    "current_page": 2,\n    "next_cursor": "eyJpZCI6NDAwfQ",\n    "has_more": true\n  }\n}

六、安全:别让你的API成为攻击入口

这是最重要的一点,也是最容易被人忽视的一点。

1. 永远不要在URL里传敏感信息

GET /orders?token=abc123&user_id=456 — 这个token会出现在日志里、浏览器历史里、代理服务器记录里。POST body或者Header才是存放敏感信息的地方。

2. 参数校验必须在后端做

前端校验是给用户看的,后端校验是给自己保命的。永远不要相信客户端传来的任何数据。

# 后端必须校验\n- 类型:id必须是整数\n- 范围:年龄不能是负数\n- 格式:邮箱、手机号要符合正则\n- 长度:用户名不能超过50字符\n- 枚举:状态只能是 pending/approved/rejected

3. 速率限制(Rate Limiting)必须有

没有速率限制的API,等着被人刷。配置合理的限流策略:

X-RateLimit-Limit: 1000\nX-RateLimit-Remaining: 999\nX-RateLimit-Reset: 1623456789

超限了返回429,而不是让服务器硬扛。


七、写在最后

API设计这事,说简单也简单,说复杂也复杂。简单在于原则就那么几条,难在于每个细节都要抠。

但凡你在设计API时偷懒,迟早会在维护时还债。而且利息很高。

好的API应该像一本好书:结构清晰、表述准确、错误有索引、文档有例子。调用你的人应该能不看文档就猜出怎么用,这才是真正的good API。

下次设计API之前,先问自己三个问题:

  1. 这个接口符合REST语义吗?
  2. 出错了,返回的状态码和body能让人一眼看懂吗?
  3. 如果这个接口被开放出去,合作方能无障碍接入吗?

如果三个问题都是YES,恭喜你,你的API不用被小龙虾吐槽了 🦞

有问题?评论区见。

相关文章

当AI开始整顿职场,我和我的AI助手都在干什么
我用AI写了一个月周报,老板问我是不是被外星人绑架了
错误处理的三重境界:为什么你的系统在半夜三点最坚强
当 AI 圈开始内卷,我决定来整点不一样的
🦞 OpenClaw 生存指南:我是怎么被一只”数字虾”套牢的
自己部署AI工具头秃?小龙虾帮你一键搞定!

发布评论