
什么是 REST首先要明确一点RESTRepresentational State Transfer实际上只是一种设计风格它并不是标准。这就是为什么网上有大量关于 REST 的最佳实践和设计指南但没有人称之为设计标准的原因。REST 的核心概念1. 面向资源的设计REST 是面向资源的这个概念非常重要。资源通过 URI统一资源标识符进行暴露。URI 的设计只需要负责把资源通过合理方式暴露出来即可。对资源的操作与 URI 无关操作是通过 HTTP 动词来体现的。因此REST 强调在 URI 中不要出现动词。正确与错误的 URI 设计对比以下示例展示了错误的设计左与正确的设计右# ❌ 错误的设计包含动词 GET /rest/api/getDogs GET /rest/api/addDogs GET /rest/api/editDogs/:dog_id GET /rest/api/deleteDogs/:dog_id ✅ 正确的设计只暴露资源 GET /rest/api/dogs # 获取所有小狗狗 POST /rest/api/dogs # 添加一个小狗狗 PUT /rest/api/dogs/:dog_id # 修改一个小狗狗 DELETE /rest/api/dogs/:dog_id # 删除一个小狗狗左边的设计明显不符合 REST 风格因为 URI 中包含了操作动词get、add、edit、delete。而右边的设计符合 REST 原则URI 只负责准确无误地暴露资源操作则通过标准的 HTTP 动词来体现。2. 充分利用 HTTP 特性REST 很好地利用了 HTTP 本身就有的一些特征如 HTTP 动词、HTTP 状态码、HTTP 报头等。REST API 是基于 HTTP 的因此你的 API 应该充分利用 HTTP 标准。这样所有的 HTTP 客户端如浏览器才能够直接理解你的 API同时也有利于缓存等优化。HTTP 动词REST 使用标准的 HTTP 动词来表示对资源的操作GET- 获取一个资源POST- 添加一个资源PUT- 修改一个资源DELETE- 删除一个资源这四个动词实际上对应着增删改查CRUD四个基本操作。HTTP 状态码REST API 应该使用恰当的 HTTP 状态码来表示操作结果200 OK- 请求成功400 Bad Request- 客户端请求错误500 Internal Server Error- 服务器内部错误在 APP 与 API 的交互中结果无非三种状态所有事情都按预期正确执行完毕 - 成功APP 发生了一些错误 - 客户端错误API 发生了一些错误 - 服务器端错误这三种状态与上述状态码是一一对应的。HTTP 报头常用的 HTTP 报头包括Authorization- 认证报头Cache-Control- 缓存报头Content-Type- 消息体类型报头......HTTP 报头还有很多不一一列举。HTTP 报头是描述 HTTP 请求或响应的元数据它的作用是客户端与服务器端进行相互通信时告诉对方应该如何处理本次请求。3. 超媒体HATEOAS超媒体是 REST 架构风格的一个重要约束全称是 Hypermedia As The Engine Of Application State。如果你对超媒体不熟悉那么超链接你一定不会陌生。简单来说超链接是实现超媒体的一种方式。超媒体希望在 REST API 中把所有资源链接起来。就像你打开一个网站的首页你看到的不仅仅是首页本身还可以通过首页查看商品、查看文章、访问论坛。超媒体就是做这个事情它利用 API 把所有资源的关系链接起来你看到的不会只是一个独立的资源而是关系网中的一个资源。虽然超媒体概念有些抽象但它是 REST 成熟度模型中的最高级别。即使你设计出了非常棒的符合超媒体的 REST API你的用户开发者也不一定能够立即接受这种设计。不过随着 API 设计理念的发展超媒体的应用正在逐渐普及。REST API 实战示例理解了 REST 的核心概念后让我们通过两个具体的框架示例来实践一下。下面分别使用 Python 的 Flask 框架和 Java 的 Spring Boot 框架实现一个简单的/dogs资源 REST API包含 GET、POST、PUT、DELETE 四个端点。1. Python Flask 示例Flask 是一个轻量级的 Python Web 框架非常适合快速构建 REST API。from flask import Flask, request, jsonify app Flask(name) 模拟数据库使用内存列表 dogs [ {id: 1, name: Buddy, breed: Golden Retriever}, {id: 2, name: Max, breed: German Shepherd} ] GET /dogs - 获取所有狗狗 app.route(/dogs, methods[GET]) def get_dogs(): return jsonify(dogs), 200 GET /dogs/id - 获取特定狗狗 app.route(/dogs/int:dog_id, methods[GET]) def get_dog(dog_id): dog next((d for d in dogs if d[id] dog_id), None) if dog: return jsonify(dog), 200 return jsonify({error: Dog not found}), 404 POST /dogs - 添加新狗狗 app.route(/dogs, methods[POST]) def create_dog(): data request.get_json() if not data or name not in data or breed not in data: return jsonify({error: Missing required fields}), 400 new_id max(d[id] for d in dogs) 1 if dogs else 1 new_dog {id: new_id, name: data[name], breed: data[breed]} dogs.append(new_dog) return jsonify(new_dog), 201 PUT /dogs/id - 更新狗狗信息 app.route(/dogs/int:dog_id, methods[PUT]) def update_dog(dog_id): data request.get_json() dog next((d for d in dogs if d[id] dog_id), None) if not dog: return jsonify({error: Dog not found}), 404 dog[name] data.get(name, dog[name]) dog[breed] data.get(breed, dog[breed]) return jsonify(dog), 200 DELETE /dogs/id - 删除狗狗 app.route(/dogs/int:dog_id, methods[DELETE]) def delete_dog(dog_id): global dogs dogs [d for d in dogs if d[id] ! dog_id] return , 204 if name main: app.run(debugTrue)代码说明使用app.route装饰器定义路由对应 REST 资源/dogsHTTP 方法GET、POST、PUT、DELETE通过methods参数指定遵循 REST 原则URI 只暴露资源/dogs操作通过 HTTP 动词体现返回适当的 HTTP 状态码200、201、204、400、404使用 JSON 格式进行数据交换2. Java Spring Boot 示例Spring Boot 是 Java 生态中构建 REST API 的主流框架提供了完整的 REST 支持。import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.*; import java.util.*; SpringBootApplication RestController RequestMapping(/dogs) public class DogController { private Listlt;Doggt; dogs new ArrayListlt;gt;(Arrays.asList( new Dog(1, Buddy, Golden Retriever), new Dog(2, Max, German Shepherd) )); // GET /dogs - 获取所有狗狗 GetMapping public Listlt;Doggt; getAllDogs() { return dogs; } // GET /dogs/{id} - 获取特定狗狗 GetMapping(/{id}) public ResponseEntitylt;?gt; getDogById(PathVariable int id) { Optionallt;Doggt; dog dogs.stream().filter(d -gt; d.getId() id).findFirst(); return dog.map(ResponseEntity::ok) .orElse(ResponseEntity.status(404).body(Dog not found)); } // POST /dogs - 添加新狗狗 PostMapping public ResponseEntitylt;Doggt; createDog(RequestBody Dog newDog) { newDog.setId(dogs.stream().mapToInt(Dog::getId).max().orElse(0) 1); dogs.add(newDog); return ResponseEntity.status(201).body(newDog); } // PUT /dogs/{id} - 更新狗狗信息 PutMapping(/{id}) public ResponseEntitylt;?gt; updateDog(PathVariable int id, RequestBody Dog updatedDog) { for (int i 0; i lt; dogs.size(); i) { if (dogs.get(i).getId() id) { updatedDog.setId(id); dogs.set(i, updatedDog); return ResponseEntity.ok(updatedDog); } } return ResponseEntity.status(404).body(Dog not found); } // DELETE /dogs/{id} - 删除狗狗 DeleteMapping(/{id}) public ResponseEntitylt;Voidgt; deleteDog(PathVariable int id) { dogs.removeIf(dog -gt; dog.getId() id); return ResponseEntity.noContent().build(); } public static void main(String[] args) { SpringApplication.run(DogController.class, args); } } // Dog 实体类 class Dog { private int id; private String name; private String breed; // 构造方法、getter、setter 省略... }代码说明使用 Spring Boot 的RestController和RequestMapping注解通过GetMapping、PostMapping、PutMapping、DeleteMapping注解对应 HTTP 方法路径参数使用PathVariable请求体使用RequestBody返回ResponseEntity可以灵活控制 HTTP 状态码和响应体遵循 REST 设计资源 URI 为/dogs操作由 HTTP 动词决定3. 示例对比与总结这两个示例都遵循了 REST 的核心原则面向资源URI 只暴露/dogs资源不包含动词利用 HTTP 特性使用标准 HTTP 动词和状态码无状态每个请求都包含所有必要信息统一接口使用 JSON 作为数据交换格式实际开发中还需要考虑数据验证、错误处理、认证授权、数据库持久化等更多细节但这两个示例展示了 REST API 的基本结构和设计思路。总结通过本文的探讨我们可以清晰地认识到 REST 不仅仅是一种技术规范更是一种面向资源的架构设计哲学。其核心价值在于通过统一的接口和标准的 HTTP 协议构建出简洁、可扩展、易于理解的 Web API。回顾 REST 的核心要点面向资源将一切抽象为资源通过 URI 唯一标识操作由 HTTP 动词体现充分利用 HTTP标准化动词、状态码和报头让 API 与 HTTP 协议无缝集成无状态通信每个请求都包含完整上下文提高系统的可伸缩性和可靠性统一接口简化客户端与服务器的交互降低学习成本超媒体驱动通过链接关系构建资源网络实现真正的 RESTful 成熟度在实际开发中无论是使用 Python Flask 还是 Java Spring Boot遵循 REST 设计原则都能带来显著的好处提高可维护性清晰的资源结构和标准化的操作方式增强互操作性任何支持 HTTP 的客户端都能轻松调用优化缓存机制充分利用 HTTP 缓存特性提升性能简化文档编写标准化的设计减少了文档的复杂性虽然 REST 设计风格已经相当成熟但在实际应用中仍需根据具体业务场景灵活调整。对于希望深入学习 REST 设计的读者我推荐参考 aisuhua/restful-api-design-references · GitHub 中收集的相关资料这些资源涵盖了从基础概念到高级实践的全方位内容。最后技术的学习永无止境。如果您对本文内容有任何疑问、建议或发现不妥之处欢迎随时指出让我们在技术交流中共同进步