接口设计规范:RESTful vs RPC、参数校验、版本控制
接口设计这个事,说起来简单,做起来坑不少。我个人习惯把接口设计分成三个维度:风格选择、参数校验 和 版本控制。这三个环节要是没想清楚,后面的联调、维护能让你头疼好几个月。
先别急着写代码。你想想看,一个对外输出的 SDK,接口就是门面。门面歪了,内部逻辑再漂亮也白搭。今天咱们就聊聊我这些年踩过的坑和总结下来的套路。
RESTful vs RPC:风格之争
接口风格这事儿,圈里争了好多年。我接手过一个项目,后端团队一半用 RESTful,一半用 RPC,联调的时候简直像两个星球的人在说话。说白了,没有的好坏,关键是看场景。
| 维度 | RESTful | RPC |
|---|---|---|
| 核心思想 | 资源导向,通过 HTTP 动词(GET/POST/PUT/DELETE)操作资源 | 动作导向,像调用本地函数一样调用远程方法 |
| URL 设计 | /users/123 表示用户资源,GET 查询,POST 创建 |
/user.getById 或 /UserService.getUser |
| 状态码 | 充分利用 HTTP 状态码(200、404、500 等) | 一般统一返回 200,内部用 error code 区分 |
| 序列化 | JSON / XML 为主,自描述 | Protobuf / Thrift / Hessian 等二进制格式,性能高 |
| 适用场景 | 开放 API、C/S 架构、资源模型清晰 | 内部微服务、高性能、强类型要求的系统 |
| 学习成本 | 较低,规范固定 | 较高,需要定义 IDL(接口定义语言) |
选型时还有个重要因素:版本控制。RESTful 可以通过 URL 路径或 Header 来区分版本,RPC 一般依赖 IDL 的兼容性设计。这部分下面细说。
参数校验:该做到的不要偷懒
「防御性编程」这个词大家都听过,但实际写代码时很容易忽略。我遇到过最离谱的事:用户传了个负数做分页参数,服务端没校验,直接导致内存溢出。你说冤不冤?
参数校验应该是 SDK 的第一道防线。我建议至少做这么几层:
- 类型校验:参数是否是期望的类型?字符串别当数字传。
- 范围校验:数值是否在合理区间?比如分页大小最大 100。
- 格式校验:邮箱、手机号、日期格式是否合法?
- 业务逻辑校验:比如删除接口,得先确认资源是否存在。
举个 Java 例子,用 JSR 303 Bean Validation 注解:
public class CreateUserRequest {
@NotBlank(message = "用户名不能为空")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 1, message = "年龄必须大于0")
@Max(value = 150, message = "年龄不能超过150")
private int age;
// getter/setter ...
}
然后在控制器里加个 @Valid 就行了,框架自动返回 400 和错误信息。
版本控制:不给升级留尾巴
接口一变,客户端不升级就崩——这是 SDK 开发者的噩梦。版本控制就是用来解决这个问题的。常见的策略有几种:
- URL 路径版本号:
/v1/users、/v2/users。最直观,但 URL 会膨胀。 - 请求头版本号: 比如
Accept: application/vnd.myapp.v2+json。干净,但调试麻烦。 - 查询参数版本号:
/users?version=2。容易缓存冲突,不推荐。 - 自定义 Header 版本号: 比如
X-API-Version: 2。灵活,但需要客户端配合。
我个人习惯在 SDK 内部维护一个版本路由表,把不同版本的处理器注册进去。例如:
// 伪代码
Map<String, VersionHandler> versionHandlers = new HashMap<>();
versionHandlers.put("v1", new V1UserHandler());
versionHandlers.put("v2", new V2UserHandler());
public void handleRequest(String version, Request request) {
VersionHandler handler = versionHandlers.get(version);
if (handler == null) {
throw new UnsupportedVersionException("不支持的版本: " + version);
}
handler.process(request);
}
这样新版本加进来,旧版本还在,客户端可以平滑迁移。记住一个原则:永远不要强制客户端立即升级,要给至少一个版本的重叠周期。
一张图看懂接口设计规范
下面这张图总结了我刚才讲的核心思路。包括风格选择、参数校验流程和版本控制的决策点。嗯,画图的时候我花了点心思,把常见坑也标出来了。
小结
接口设计规范不是教条,是无数趟坑之后总结出来的经验。RESTful 和 RPC 没有的优劣,关键看你的使用场景。参数校验别偷懒,那是最后一道防线。版本控制要提前想好,否则后面改一个字段,客户端全挂。
养成好习惯,从每一个接口设计开始。