3. RESTful API设计原则:资源命名规范、HTTP动词使用、状态码含义、API版本管理
好,咱们今天聊点实在的。RESTful API,说白了就是一套让客户端和服务器好好说话的规矩。我做了这么多年桌面应用,跟后端API打交道的时间比跟UI打交道还多。你想想看,一个桌面应用再漂亮,如果网络请求写得一塌糊涂,用户照样摔键盘。
这一章,我就把RESTful API设计里最核心的几个点掰开揉碎讲给你听。资源怎么命名、动词怎么用、状态码怎么选、版本怎么管——这些都是我踩过坑之后总结出来的经验。
3.1 资源命名规范:让URL像文件路径一样清晰
资源命名,是RESTful API的门面。我见过太多乱七八糟的URL了,比如 /getUserInfo、/delete_order、/api/v1/updateProduct。嗯,这些写法不能说错,但离「优雅」差得远。
核心原则就一条:用名词,不用动词。
为什么?因为HTTP动词已经表达了操作意图。你再用动词就是画蛇添足。我个人习惯把URL当作「资源地址」,而不是「操作指令」。
✅ 推荐写法:
/users— 用户列表/users/123— 某个用户/orders/456/items— 某个订单下的商品
❌ 不推荐写法:
/getUsers/deleteUserById/api/updateOrderStatus
还有几个小细节要注意:
- 用复数名词:
/users而不是/user。统一用复数,省得纠结。 - 用连字符分隔单词:
/order-items而不是/orderItems或/order_items。URL不区分大小写,下划线在某些浏览器里会被吞掉。 - 层级关系用斜杠表示:
/users/123/orders表示「用户123的订单」。不要搞成/orders?userId=123,除非是过滤条件。
我的小技巧: 设计URL时,想象你在操作一个文件系统。每个资源就是一个文件夹或文件,路径越短越好,但信息要完整。
3.2 HTTP动词使用:GET/POST/PUT/DELETE 各司其职
HTTP动词,就是你对资源做的「操作」。很多新手喜欢只用GET和POST,其他动词一概不用。我在项目中遇到过这种情况:一个团队用POST干所有事,结果API文档写得比小说还长。
其实就四个动词,记清楚就行:
| 动词 | 作用 | 幂等 | 示例 |
|---|---|---|---|
| GET | 获取资源 | 是 | GET /users/123 |
| POST | 创建资源 | 否 | POST /users |
| PUT | 完整更新资源 | 是 | PUT /users/123 |
| DELETE | 删除资源 | 是 | DELETE /users/123 |
这里有个坑: PUT和PATCH的区别。PUT是「全量替换」,你传什么字段,资源就变成什么字段。PATCH是「局部更新」,只改你传的字段。我个人习惯:如果更新字段少,用PATCH;如果整个对象都变了,用PUT。
⚠️ 注意: POST不是幂等的。你调两次POST,会创建两个资源。而GET、PUT、DELETE调多少次结果都一样。这个特性在重试机制里特别重要——我曾经因为没注意幂等性,导致用户下了两笔重复订单,被产品经理追着骂了一下午。
3.3 状态码含义:让客户端一眼看懂发生了什么
状态码,是服务器给客户端的「表情」。你返回200,客户端就知道一切正常;返回404,客户端就知道资源没找到。但很多人只用了200和500,其他状态码一概不用。这就像你跟人说话,只会说「好」和「不好」,太粗糙了。
我建议至少掌握这几类:
- 2xx 成功:
200 OK— GET、PUT、PATCH成功201 Created— POST创建成功,记得在响应头里返回Location指向新资源204 No Content— DELETE成功,不需要返回内容
- 4xx 客户端错误:
400 Bad Request— 参数格式不对,比如JSON解析失败401 Unauthorized— 没登录或token过期403 Forbidden— 登录了但没权限404 Not Found— 资源不存在409 Conflict— 资源冲突,比如重复创建422 Unprocessable Entity— 参数校验失败,比如邮箱格式不对
- 5xx 服务端错误:
500 Internal Server Error— 服务器炸了,别让用户看到堆栈信息502 Bad Gateway— 上游服务挂了503 Service Unavailable— 服务过载或维护中
避坑指南: 我曾经见过一个API,不管什么错误都返回200,然后在响应体里放一个 {"code": -1, "message": "xxx"}。这种做法让客户端代码变得极其丑陋——每次请求都要先解析响应体,再判断业务状态码。记住:HTTP状态码是给协议层用的,业务状态码是给应用层用的,别混在一起。
3.4 API版本管理:别让旧客户端崩掉
API版本管理,说白了就是「向前兼容」。你升级了API,不能把老版本的客户端搞崩。我见过最惨的一次:后端改了接口返回格式,没通知前端,结果桌面应用直接白屏,用户数据全丢了。
常见的版本管理方式有三种:
| 方式 | 示例 | 优点 | 缺点 |
|---|---|---|---|
| URL路径 | /api/v1/users |
简单直观,容易路由 | 版本号污染URL |
| 请求头 | Accept: application/vnd.myapp.v2+json |
URL干净,符合RESTful | 调试麻烦,浏览器不友好 |
| 查询参数 | /api/users?version=2 |
实现简单 | 容易被缓存,语义不清晰 |
我个人习惯用URL路径方式。虽然有人觉得不够「纯粹」,但胜在直观。你想想看,桌面应用的日志里看到 /api/v2/users,一眼就知道用的是哪个版本,不用去翻请求头。
我的建议: 版本号用整数,别用小数点。比如 v1、v2,而不是 v1.1、v1.2。为什么?因为小版本号通常意味着向后兼容的改动,没必要暴露给客户端。只有不兼容的改动(比如删字段、改参数类型)才需要升大版本。
还有一点:不要轻易废弃旧版本。桌面应用不像网页,用户不会自动更新。你至少要给用户3-6个月的过渡期,并在响应头里加一个 Deprecation: true 标记,提醒客户端该升级了。
⚠️ 我曾经踩过的坑: 有一次我升级了API,把 /api/v1/users 直接删了,结果有十几个企业客户用的还是旧版桌面应用,第二天客服电话被打爆。从那以后,我定了个规矩:旧版本至少保留6个月,并且在日志里记录每个版本的调用次数,低于1%时才考虑下线。
3.5 总结:设计API时问自己三个问题
好了,这一章的内容差不多就这些。最后送你三个问题,每次设计API时问自己一遍:
- 这个URL像不像一个资源? 如果URL里出现了动词,说明设计有问题。
- 这个状态码客户端能看懂吗? 别返回200表示错误,也别返回500表示参数不对。
- 如果明天改了接口,旧客户端会崩吗? 如果会,赶紧加版本号。
记住:好的API设计,是让调用者觉得「这很自然,本来就应该这样」。而不是让调用者翻着文档骂「这谁设计的破接口」。嗯,咱们做桌面应用的,尤其要注意这一点——用户可没耐心看你的API文档。