2. 接口设计基本原则:RESTful、HTTP方法、状态码
聊接口设计,绕不开RESTful。很多新人一听就觉得这是“标准规范”,得背下来。我个人倒是觉得,RESTful更像一套设计哲学,它告诉我们怎么用HTTP原生的东西把事情说清楚。
说白了,RESTful不是强迫你用哪个框架,而是让你尊重HTTP本身。你想想看,HTTP已经有了GET、POST、PUT、DELETE这些动词,还有状态码来表达结果,为什么还要自己再包一层“action=delete”的参数?
2.1 RESTful 设计原则
RESTful的核心就一句话:把每个“东西”抽象成资源,用URI定位,用HTTP方法操作。
- 资源导向:设计的是资源,不是动作。比如
/secrets代表一堆密钥,/secrets/123代表某个密钥。 - 无状态:服务端不存客户端上下文。每个请求都带齐所有需要的信息。
- 统一接口:所有资源都通过相同的方法操作,不搞特殊。
- 表现层分离:资源的结构和它的展示形式分开。你可以返回JSON、XML甚至YAML,但资源本身不变。
我当时的经验:有一次接手一个旧项目,他们把“获取密钥列表”设计成 POST /getSecrets。我改成了 GET /secrets,测试一跑,一堆客户端报错。嗯,这就是没理解“资源”的含义。
不过要注意,RESTful没有规定URI必须怎么拼,但业内有一些约定俗成的写法。比如用复数名词、小写、连字符代替下划线。
2.2 HTTP 方法的选择
HTTP方法说白了就是动词。对于Secrets接口,最常用的就这么几个:
| 方法 | 用途 | 幂等 | 安全 |
|---|---|---|---|
| GET | 读取资源 | 是 | 是 |
| POST | 创建资源 | 否 | 否 |
| PUT | 整体替换资源 | 是 | 否 |
| PATCH | 部分更新资源 | 否 | 否 |
| DELETE | 删除资源 | 是 | 否 |
小提示:幂等意味着你调一次和调十次,资源最终状态一样。PUT很典型——你把密钥正文改成"abc",重复调用还是"abc"。但POST每次都会新建一个,所以不幂等。
我曾经在一家云厂商做过SDK,发现很多人把更新密钥做成POST加参数 ?action=update。结果重复提交时生成了多条记录,生产环境直接炸了。后来强制要求必须用PUT或PATCH,才解决。
具体怎么选?我个人的做法是:
- 读数据 →
GET - 创建新资源(ID由服务端生成) →
POST - 完整替换(ID客户端指定) →
PUT - 部分更新 →
PATCH - 删除 →
DELETE
有个坑要注意:PATCH不是必须幂等的,但很多网关和中间件会把PATCH当非幂等处理。如果你的场景需要重试机制,建议用PUT代替PATCH,或者保证你的PATCH操作本身是幂等的。
2.3 状态码:让客户端看懂发生了什么
状态码是HTTP返回结果的第一行信息。很多开发者只记得200和500,其实多用状态码能省很多沟通成本。
我习惯把状态码分四组来记:
| 范围 | 含义 | 常见例子 |
|---|---|---|
| 2xx | 成功 | 200 OK, 201 Created, 204 No Content |
| 3xx | 重定向 | 301 Moved Permanently, 304 Not Modified |
| 4xx | 客户端错误 | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict |
| 5xx | 服务端错误 | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable |
对于Secrets接口,有几个状态码特别重要:
- 201 Created:创建成功时返回,附带Location头指向新资源。
- 204 No Content:删除成功或更新成功但不需要返回体时用。
- 400 Bad Request:请求体格式错误、缺少必填字段。
- 401 Unauthorized:没带或无效。
- 403 Forbidden:有但没权限读这个密钥。
- 404 Not Found:密钥不存在。
- 409 Conflict:版本冲突,比如并发更新时。
- 429 Too Many Requests:限流触发。
避坑指南:我曾经见过一个团队,所有错误都返回200,然后在业务JSON里塞个“errorCode”。结果客户端全得解析JSON才知道请求失败。别这么做——直接用HTTP状态码表达结果,错误详情放body里。
举个实际例子,假设我们要创建一个密钥:
POST /secrets
Content-Type: application/json
{
"name": "my-",
"value": "sk-xxxx",
"type": "api"
}
// 成功返回
201 Created
Location: /secrets/my-
如果密钥已经存在:
409 Conflict
{
"error": "secret_already_exists",
"message": "A secret with name 'my-' already exists"
}
2.4 核心知识图谱
下面这张图把上面三块内容串起来了。你会发现,RESTful原则是骨架,HTTP方法是动词,状态码是反馈。三者缺一不可。
我建议你在设计每个Secrets接口时,都先对照这张图过一遍:资源URI对吗?用了正确的方法吗?状态码能准确传达结果吗?跑通一遍流程,基本就不会出大问题。
2.5 小结
接口设计不是玄学,它就是选对动词、选对号码。RESTful给了我们一套通用的交流语言,HTTP方法定义了“做什么”,状态码告诉“结果怎样”。这三样东西搭起来,接口就清晰了。