news 2026/8/20 15:05:21

RPC和REST区别

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RPC和REST区别

什么是 REST?

首先要明确一点:REST(Representational 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 的交互中,结果无非三种状态:

  1. 所有事情都按预期正确执行完毕 - 成功
  2. APP 发生了一些错误 - 客户端错误
  3. 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(debug=True)

代码说明:

  • 使用@app.route装饰器定义路由,对应 REST 资源/dogs
  • HTTP 方法(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 List&lt;Dog&gt; dogs = new ArrayList&lt;&gt;(Arrays.asList( new Dog(1, "Buddy", "Golden Retriever"), new Dog(2, "Max", "German Shepherd") )); // GET /dogs - 获取所有狗狗 @GetMapping public List&lt;Dog&gt; getAllDogs() { return dogs; } // GET /dogs/{id} - 获取特定狗狗 @GetMapping("/{id}") public ResponseEntity&lt;?&gt; getDogById(@PathVariable int id) { Optional&lt;Dog&gt; 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 ResponseEntity&lt;Dog&gt; 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 ResponseEntity&lt;?&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 ResponseEntity&lt;Void&gt; 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 的核心原则:

  1. 面向资源:URI 只暴露/dogs资源,不包含动词
  2. 利用 HTTP 特性:使用标准 HTTP 动词和状态码
  3. 无状态:每个请求都包含所有必要信息
  4. 统一接口:使用 JSON 作为数据交换格式

实际开发中,还需要考虑数据验证、错误处理、认证授权、数据库持久化等更多细节,但这两个示例展示了 REST API 的基本结构和设计思路。

总结

通过本文的探讨,我们可以清晰地认识到 REST 不仅仅是一种技术规范,更是一种面向资源的架构设计哲学。其核心价值在于通过统一的接口和标准的 HTTP 协议,构建出简洁、可扩展、易于理解的 Web API。

回顾 REST 的核心要点:

  • 面向资源:将一切抽象为资源,通过 URI 唯一标识,操作由 HTTP 动词体现
  • 充分利用 HTTP:标准化动词、状态码和报头,让 API 与 HTTP 协议无缝集成
  • 无状态通信:每个请求都包含完整上下文,提高系统的可伸缩性和可靠性
  • 统一接口:简化客户端与服务器的交互,降低学习成本
  • 超媒体驱动:通过链接关系构建资源网络,实现真正的 RESTful 成熟度

在实际开发中,无论是使用 Python Flask 还是 Java Spring Boot,遵循 REST 设计原则都能带来显著的好处:

  1. 提高可维护性:清晰的资源结构和标准化的操作方式
  2. 增强互操作性:任何支持 HTTP 的客户端都能轻松调用
  3. 优化缓存机制:充分利用 HTTP 缓存特性提升性能
  4. 简化文档编写:标准化的设计减少了文档的复杂性

虽然 REST 设计风格已经相当成熟,但在实际应用中仍需根据具体业务场景灵活调整。对于希望深入学习 REST 设计的读者,我推荐参考 aisuhua/restful-api-design-references · GitHub 中收集的相关资料,这些资源涵盖了从基础概念到高级实践的全方位内容。

最后,技术的学习永无止境。如果您对本文内容有任何疑问、建议或发现不妥之处,欢迎随时指出,让我们在技术交流中共同进步!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/20 15:02:22

计算机单片机毕设实战-基于 STM32 单片机的智能水族养殖设备控制系统设计 基于 STM32 的水温水位光照浑浊度综合监控系统设计(012304)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/8/20 15:01:22

Rust构建AI Agent网络搜索工具:从基础HTTP请求到生产级集成

最近在折腾 AI Agent 开发&#xff0c;发现一个挺有意思的现象&#xff1a;很多教程和开源项目&#xff0c;一讲到“工具调用”&#xff0c;尤其是网络搜索这类看似基础的功能&#xff0c;要么直接甩给你一个封装好的 API 调用示例&#xff0c;要么就默认你已经理解了背后的所有…

作者头像 李华
网站建设 2026/8/20 14:59:23

别乱选投票小程序!真正好用的免费款在这里

你是不是也遇到过这种情况&#xff1a;临时要办一场评选活动&#xff0c;随手找了个投票小程序&#xff0c;结果活动做到一半&#xff0c;页面弹窗提示“导出数据需开通VIP”&#xff0c;或者链接刚发出去就被刷票大军攻陷&#xff0c;更糟心的是活动页面突然卡死&#xff0c;几…

作者头像 李华
网站建设 2026/8/20 14:54:24

Windows 看B站怎么更省内存?BiliBili-UWP 第三方客户端快速上手攻略

Windows 看B站怎么更省内存&#xff1f;BiliBili-UWP 第三方客户端快速上手攻略 【免费下载链接】BiliBili-UWP BiliBili的UWP客户端&#xff0c;当然&#xff0c;是第三方的了 项目地址: https://gitcode.com/gh_mirrors/bi/BiliBili-UWP 一台老笔记本同时开着浏览器和…

作者头像 李华