RESTful规范
好的,我们来系统地讲解一下 RESTful 规范。它不仅仅是一种 URL 风格,更是一套架构设计原则。
什么是 RESTful?
REST(Representational State Transfer)是一种软件架构风格,由 Roy Fielding 博士在 2000 年提出。RESTful 就是遵循 REST 原则的 API 设计规范。
核心原则(六大约束)
1. 统一接口
这是最重要的原则,包含多个方面:
HTTP 方法语义化
| 方法 | 语义 | 幂等性 | 安全 |
|---|---|---|---|
GET | 获取资源 | ✅ 是 | ✅ 是 |
POST | 创建资源 | ❌ 否 | ❌ 否 |
PUT | 更新/创建资源 | ✅ 是 | ❌ 否 |
DELETE | 删除资源 | ✅ 是 | ❌ 否 |
PATCH | 部分更新资源 | ❌ 否 | ❌ 否 |
资源标识
- 每个资源都有唯一的 URI
- URI 只标识资源,不包含操作
// ✅ 正确 - URI 标识资源
GET /users/123
PUT /users/123
DELETE /users/123// ❌ 错误 - URI 包含操作
GET /getUser/123
POST /updateUser/123
GET /deleteUser/123
2. 无状态
服务器不保存客户端的状态信息。
// ✅ 正确 - 每次请求都包含认证信息
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id,@RequestHeader("Authorization") String token) {// 根据 token 验证权限
}// ❌ 错误 - 服务器保存会话状态
// (依赖服务器端的 Session)
3. 可缓存
响应应该明确表明是否可缓存。
@GetMapping("/products/{id}")
public ResponseEntity<Product> getProduct(@PathVariable Long id) {Product product = productService.findById(id);return ResponseEntity.ok().cacheControl(CacheControl.maxAge(30, TimeUnit.MINUTES)).eTag(product.getVersion().toString()).body(product);
}
4. 客户端-服务器分离
前端与后端分离,各自独立演化。
5. 分层系统
系统可以分层,每层只知道相邻层。
6. 按需代码(可选)
服务器可以传输可执行代码给客户端。
RESTful API 设计规范
URI 设计规范
使用名词,而不是动词
// ✅ 正确
GET /users // 获取用户列表
POST /users // 创建用户
GET /users/123 // 获取特定用户
PUT /users/123 // 更新用户
DELETE /users/123 // 删除用户// ❌ 错误
GET /getUsers
POST /createUser
GET /getUser/123
POST /updateUser/123
GET /deleteUser/123
使用复数名词
// ✅ 推荐
GET /users/123/orders // 获取用户的订单// ❌ 不推荐
GET /user/123/order
资源层级关系
// 用户的所有订单
GET /users/123/orders// 用户的特定订单
GET /users/123/orders/456// 订单的所有商品
GET /users/123/orders/456/items
HTTP 状态码规范
| 状态码 | 含义 | 使用场景 |
|---|---|---|
200 OK | 成功 | GET、PUT 成功 |
201 Created | 创建成功 | POST 创建资源成功 |
204 No Content | 成功无返回体 | DELETE 成功 |
400 Bad Request | 请求错误 | 参数验证失败 |
401 Unauthorized | 未认证 | 缺少或错误认证 |
403 Forbidden | 无权限 | 认证成功但无权限 |
404 Not Found | 资源不存在 | 资源 ID 不存在 |
500 Internal Server Error | 服务器错误 | 服务器内部异常 |
响应体规范
统一响应格式
@Data
public class Result<T> {private Integer code; // 业务状态码private String message; // 提示信息private T data; // 响应数据private Long timestamp; // 时间戳public static <T> Result<T> success(T data) {Result<T> result = new Result<>();result.setCode(200);result.setMessage("success");result.setData(data);result.setTimestamp(System.currentTimeMillis());return result;}
}
分页响应
@Data
public class PageResult<T> {private List<T> records;private Long total;private Integer size;private Integer current;public static <T> PageResult<T> success(Page<T> page) {PageResult<T> result = new PageResult<>();result.setRecords(page.getContent());result.setTotal(page.getTotalElements());result.setSize(page.getSize());result.setCurrent(page.getNumber() + 1);return result;}
}
完整示例
Controller 实现
@RestController
@RequestMapping("/api/v1/users")
public class UserController {@Autowiredprivate UserService userService;// 获取用户列表(带分页和过滤)@GetMappingpublic Result<PageResult<User>> getUsers(@RequestParam(defaultValue = "0") Integer page,@RequestParam(defaultValue = "10") Integer size,@RequestParam(required = false) String name) {Page<User> users = userService.findUsers(page, size, name);return Result.success(PageResult.success(users));}// 获取特定用户@GetMapping("/{id}")public Result<User> getUser(@PathVariable Long id) {User user = userService.findById(id);return Result.success(user);}// 创建用户@PostMappingpublic Result<User> createUser(@RequestBody @Valid UserCreateRequest request) {User user = userService.create(request);return Result.success(user);}// 更新用户(完整更新)@PutMapping("/{id}")public Result<User> updateUser(@PathVariable Long id,@RequestBody @Valid UserUpdateRequest request) {User user = userService.update(id, request);return Result.success(user);}// 部分更新用户@PatchMapping("/{id}")public Result<User> patchUser(@PathVariable Long id,@RequestBody Map<String, Object> updates) {User user = userService.patch(id, updates);return Result.success(user);}// 删除用户@DeleteMapping("/{id}")public Result<Void> deleteUser(@PathVariable Long id) {userService.delete(id);return Result.success();}// 用户的订单资源@GetMapping("/{userId}/orders")public Result<List<Order>> getUserOrders(@PathVariable Long userId) {List<Order> orders = userService.findUserOrders(userId);return Result.success(orders);}
}
对应的 HTTP 请求示例
# 获取用户列表
GET /api/v1/users?page=0&size=20&name=张三# 获取特定用户
GET /api/v1/users/123# 创建用户
POST /api/v1/users
Content-Type: application/json
{"name": "李四", "email": "lisi@example.com"}# 更新用户
PUT /api/v1/users/123
Content-Type: application/json
{"name": "李四新", "email": "lisi_new@example.com"}# 删除用户
DELETE /api/v1/users/123# 获取用户的订单
GET /api/v1/users/123/orders
总结
RESTful 规范的核心要点:
- URL 设计:使用名词表示资源,HTTP 方法表示操作
- HTTP 语义:正确使用状态码和方法
- 无状态:每次请求都包含完整信息
- 统一接口:一致的 API 设计风格
- 资源导向:一切都是资源,通过 URI 标识
遵循这些规范可以让你的 API 更加:
- 可预测:开发者容易理解和使用
- 可扩展:易于添加新功能
- 可维护:代码结构清晰
- 跨平台:前后端分离,支持多种客户端
