RESTful 与 RPC
问题
RESTful API 和 RPC 有什么区别?如何设计好的 RESTful API?
答案
REST vs RPC 对比
| 维度 | RESTful | RPC(如 gRPC) |
|---|---|---|
| 风格 | 资源导向(URL = 资源) | 操作导向(函数调用) |
| 协议 | HTTP | HTTP/2、TCP |
| 数据格式 | JSON(文本) | Protobuf(二进制) |
| 性能 | 一般 | 高(序列化快、数据小) |
| 可读性 | 高(浏览器可直接访问) | 低(需要工具) |
| 适用场景 | 对外 API、前后端通信 | 微服务间内部通信 |
RESTful API 设计原则
# 资源命名:名词复数
GET /api/users # 获取用户列表
GET /api/users/123 # 获取指定用户
POST /api/users # 创建用户
PUT /api/users/123 # 全量更新用户
PATCH /api/users/123 # 部分更新
DELETE /api/users/123 # 删除用户
# 嵌套资源
GET /api/users/123/orders # 获取用户的订单
POST /api/users/123/orders # 为用户创建订单
# 查询参数
GET /api/users?page=1&size=20&sort=name,asc
GET /api/users?status=active&role=admin
统一响应格式
Spring Boot 统一响应
@Data
@AllArgsConstructor
public class ApiResponse<T> {
private int code;
private String message;
private T data;
public static <T> ApiResponse<T> ok(T data) {
return new ApiResponse<>(200, "success", data);
}
public static <T> ApiResponse<T> error(int code, String message) {
return new ApiResponse<>(code, message, null);
}
}
// 正常响应
// { "code": 200, "message": "success", "data": { "id": 1, "name": "张三" } }
// 错误响应
// { "code": 400, "message": "参数不合法", "data": null }
幂等性
| 方法 | 幂等 | 说明 |
|---|---|---|
| GET | ✅ | 多次获取结果相同 |
| PUT | ✅ | 多次全量更新结果相同 |
| DELETE | ✅ | 删除已删除的资源不报错 |
| POST | ❌ | 多次提交可能创建多条 |
非幂等接口需要在业务层保证幂等(Token 机制、唯一约束等),详见 幂等性设计。
常见面试问题
Q1: 什么时候用 REST、什么时候用 RPC?
答案:
- 对外 API / 前后端通信:REST,可读性好,标准化
- 微服务内部通信:gRPC,性能高,支持流式通信
- 两者结合:网关对外暴露 REST,服务间用 gRPC
Q2: REST API 版本控制怎么做?
答案:
| 方式 | 示例 | 优缺点 |
|---|---|---|
| URL 路径 | /api/v1/users | 简单直观,最常用 |
| Header | Accept: application/vnd.api.v1+json | URL 干净,但不直观 |
| 查询参数 | /api/users?version=1 | 简单,但语义不清 |
Q3: gRPC 有什么优势?
答案:
- 性能高:Protobuf 二进制序列化,比 JSON 小 3-10 倍
- 多语言:.proto 文件自动生成各语言代码
- 流式通信:支持客户端流、服务端流、双向流
- HTTP/2:多路复用、头部压缩
详见 服务通信。