3、RESTful通信:RESTful API设计原则、HTTP方法在Adaptive中的应用、资源表示与状态码
好,咱们进入第三章。RESTful通信,说白了就是咱们Adaptive平台跟外界打交道的那张嘴。你想想看,一个通信系统再牛,如果跟外部系统说不上话,那跟废铁有什么区别?我个人习惯,在设计API之前,先想清楚三个问题:谁在调用?调用来干嘛?返回什么?想明白了,设计起来就顺了。
3.1 RESTful API设计原则——别把简单事情搞复杂
RESTful设计,核心就六个字:资源、动作、表述。我在项目中遇到过不少团队,一上来就搞什么「/getUserInfo」、「/deleteOrder」这种RPC风格的接口。嗯,这其实违背了REST的初衷。REST是把一切都看作资源,用HTTP方法来表达操作。
几个关键原则,我列一下:
- 资源导向:URL只表示资源,不表示动作。比如
/users表示用户集合,/users/123表示某个用户。 - 无状态:每个请求都包含所有必要信息,服务器不保存客户端状态。说白了,这次请求跟上次没关系。
- 统一接口:用标准的HTTP方法(GET、POST、PUT、DELETE等)来操作资源。
- 超媒体驱动:响应里带上链接,告诉客户端下一步能做什么。这个在Adaptive里用得不多,但了解没坏处。
核心要点:RESTful API的URL应该是名词复数形式,用斜杠表示层级关系,用查询参数做过滤和分页。千万别在URL里出现动词。
举个例子,咱们Adaptive平台里有个设备管理模块。错误的做法是 /getDeviceStatus?id=5,正确的做法是 /devices/5/status。你看,一目了然。
3.2 HTTP方法在Adaptive中的应用——每个动词都有它的脾气
HTTP方法,说白了就是告诉服务器你想干嘛。Adaptive平台里,我主要用这么几个:
| HTTP方法 | 用途 | Adaptive中的典型场景 | 幂等性 |
|---|---|---|---|
| GET | 获取资源 | 查询设备列表、获取配置 | 是 |
| POST | 创建资源 | 注册新设备、提交告警 | 否 |
| PUT | 全量更新 | 更新设备配置(整体替换) | 是 |
| PATCH | 部分更新 | 修改设备某个参数 | 否 |
| DELETE | 删除资源 | 移除设备、清除日志 | 是 |
这里有个坑,我踩过。POST和PUT的区别,很多人搞混。POST是不幂等的,你发两次可能创建两个资源。PUT是幂等的,发多少次结果都一样。我曾经在项目里用PUT做创建,结果客户端重试时生成了重复数据,排查了半天才发现问题。
避坑指南:我曾经在Adaptive的告警接口里,用POST来更新告警状态。后来发现告警被重复处理了。正确的做法是:创建用POST,全量更新用PUT,部分更新用PATCH。别混着用。
再补充一点,Adaptive平台里有个特殊场景——批量操作。比如批量注册设备,我建议用POST到集合资源,请求体里放一个数组。别搞什么 /batchCreateDevices,那又回到RPC的老路上了。
3.3 资源表示与状态码——你给出去的,决定了别人怎么用
资源表示,就是服务器返回的数据长什么样。Adaptive平台里,我统一用JSON格式。为什么?轻量、易读、解析快。XML?嗯,除非有特殊要求,否则别碰。
一个标准的资源表示,应该包含三部分:
- 数据本身:比如设备ID、名称、状态等
- 链接:关联资源的URL,方便客户端导航
- 元数据:比如创建时间、更新时间、版本号等
举个例子,获取某个设备的响应:
{
"id": "dev-001",
"name": "基站A-3号",
"status": "online",
"location": "机房B-2",
"created_at": "2024-01-15T08:30:00Z",
"updated_at": "2024-03-20T14:22:00Z",
"_links": {
"self": { "href": "/devices/dev-001" },
"metrics": { "href": "/devices/dev-001/metrics" },
"alarms": { "href": "/devices/dev-001/alarms" }
}
}
你看,我习惯在响应里带上 _links 字段。这样客户端拿到数据后,不用硬编码URL,直接跟着链接走就行。这在Adaptive的微服务架构里特别有用,服务地址变了也不影响客户端。
小技巧:我个人习惯在响应里加一个 version 字段,比如 "version": "1.0"。这样接口升级时,客户端可以根据版本号做兼容处理。别问我为什么,问就是被坑过。
再说状态码。HTTP状态码不是随便选的,每个数字都有它的含义。我见过有人不管成功失败都返回200,然后在响应体里放一个 code 字段表示业务状态。嗯,这其实是在绕开HTTP协议,不推荐。
Adaptive平台里,我常用的状态码:
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 200 OK | 请求成功 | GET、PUT、PATCH成功 |
| 201 Created | 资源创建成功 | POST成功创建资源 |
| 204 No Content | 请求成功,无返回体 | DELETE成功 |
| 400 Bad Request | 请求参数错误 | 缺少必填字段、格式错误 |
| 401 Unauthorized | 未认证 | 缺少或无效的认证令牌 |
| 403 Forbidden | 无权限 | 认证通过但权限不足 |
| 404 Not Found | 资源不存在 | 请求的资源ID无效 |
| 409 Conflict | 资源冲突 | 创建重复资源、版本冲突 |
| 422 Unprocessable Entity | 语义错误 | 业务逻辑校验失败 |
| 500 Internal Server Error | 服务器内部错误 | 未捕获的异常 |
这里有个细节要注意。404和403的区别,很多人搞混。404是「找不到」,403是「不让看」。你想想看,如果用户没权限访问某个设备,你返回404,他以为设备不存在。返回403,他才知道是权限问题。我建议统一用403,别藏着掖着。
经验之谈:错误响应里,除了状态码,还要带上错误信息。我习惯用这样的格式:{"error": {"code": "DEVICE_NOT_FOUND", "message": "设备 dev-999 不存在"}}。这样客户端拿到后,可以直接展示给用户,或者做本地化处理。
最后说一句,RESTful设计没有银弹。Adaptive平台里,有些场景可能不适合纯REST,比如实时数据推送、长轮询等。这时候该用WebSocket就用WebSocket,别死磕REST。设计API,最终目的是让调用方用得舒服,不是炫技。
好,这一章就到这儿。下一章咱们聊聊消息队列在Adaptive里的应用,那可是异步通信的利器。