其他

什么是REST?

自从Roy Fielding博士在2000年他的博士论文中提出REST(Representational State Transfer)风格的软件架构模式后,REST就基本上迅速取代了复杂而笨重的SOAP,成为Web API的标准了。

什么是Web API呢?


如果我们想要获取某个电商网站的某个商品,输入http://localhost:3000/products/123,就可以看到id为123的商品页面,但这个结果是HTML页面,它同时混合包含了Product的数据和Product的展示两个部分。对于用户来说,阅读起来没有问题,但是,如果机器读取,就很难从HTML中解析出Product的数据。

如果一个URL返回的不是HTML,而是机器能直接解析的数据,这个URL就可以看成是一个Web API。比如,读取http://localhost:3000/api/products/123,如果能直接返回Product的数据,那么机器就可以直接读取。

REST就是一种设计API的模式。最常用的数据格式是JSON。由于JSON能直接被JavaScript读取,所以,以JSON格式编写的REST风格的API具有简单、易读、易用的特点。

编写API有什么好处呢?由于API就是把Web App的功能全部封装了,所以,通过API操作数据,可以极大地把前端和后端的代码隔离,使得后端代码易于测试,前端代码编写更简单。

此外,如果我们把前端页面看作是一种用于展示的客户端,那么API就是为客户端提供数据、操作数据的接口。这种设计可以获得极高的扩展性。例如,当用户需要在手机上购买商品时,只需要开发针对iOS和Android的两个客户端,通过客户端访问API,就可以完成通过浏览器页面提供的功能,而后端代码基本无需改动。

当一个Web应用以API的形式对外提供功能时,整个应用的结构就扩展为:

把网页视为一种客户端,是REST架构可扩展的一个关键。

什么是REST?


2000年,Roy Thomas Fielding在博士论文中提出REST软件架构风格,描述如何使用这种架构风格来指导基于网络的应用架构设计。
REST是指导WEB应用架构设计和开发的,比如Spring框架就是一种REST风格的架构设计,从时间线上来说,Spring框架在2002年4月份发布1.0,SpringBoot是2014年才发布的。
所以它对互联网发展的影响比较深远,也有人把REST称为“WEB软件架构设计的圣经”。

资源和资源定位符


REST是通过统一资源标识符(URI)来标识资源的,这个资源是指两个组件交互的所涉及的文本、图片或音视频等。

这句话是理解REST的核心。

更简单点来说:REST是一个抽象概念,定义了用来操作资源的约束条件,以URI的形式曝露的约束,定义的是约束,是准则,可以使用这种约束和准则去编写程序,可以解决程序存在的某些问题。

就跟造概念车一样。车还没造好,先想好整部车的外观、发动机、地盘、内饰等,将各种不切实际的想象进行了一种条件限制,比如轮胎必须是圆的,哈哈。后面造车只能按约定好的这个形状这个搭配这个限制,而不是奇形怪状的一堆零件组合。

刚刚说解决问题,解决什么问题呢?继续往下看。

解决什么问题


1. 统一接口,统一URI

原来可能我们是这样定义接口的:

http://xxx.com/api/v1/getUserInfo
http://xxx.com/api/v1/addUserInfo
http://xxx.com/api/v1/updateUserInfo
http://xxx.com/api/v1/deleteUserInfo

REST规范定义接口

http://xxx.com/api/v1/user, GET, 获取用户信息
http://xxx.com/api/v1/user, POST, 新增用户信息
http://xxx.com/api/v1/user, PUT,  修改用户信息
http://xxx.com/api/v1/user, DELETE, 删除用户信息

看着变化不是非常大,但其实规范了整个资源的URI都是/api/v1/user。

这种定义上的规范化,会随着系统功能的不断增加,所需资源的不断加入,系统整体清晰明了。

不至于不同的开发者同一个资源下写出N多不同的URI,日积月累系统就变得混乱不堪,可读性和健壮性会比较差,维护成本也会相应提高。

2. 不需要有状态才能操作

REST约束:客户端和服务器在通信上是无状态的。

无状态是指客户端到服务器的每一个请求都包含了这次请求所需要的信息。

举个栗子:比如月底发工资了,你需要查询这个月薪资的薪资明细。需要先登录,登录后才能进行查询。登录就是一种状态,没有登录系统就查不了,因此它是有状态的,有依赖条件的。
如果是REST方式,只要你传给服务器说明需要查询哪个用户的信息,服务器在验证你的身份后,把薪资5000,扣了社保100,公积金200这些详细信息返回给你。

无状态的方式优点明显:① 客户端对服务器没有依赖,不需要做查询薪资以外的登录操作。② 两者之间不相互影响,不会因某个小故障而需要做额外的工作,系统变得更可靠。③ 每次请求后马上释放服务器资源,不必在不同的请求中保存状态,服务器伸缩性更强了。

无状态需要验证身份是因为不是随便谁都可以请求资源查到你的薪资的。当然,这样做的缺点是,每查询一次,都要将验证信息发送过去,网络交互的开销会增加,网络性能会受影响。

3.可缓存请求

服务器可以标记响应的内容是否可以被客户端缓存。如果是可缓存的,那么客户端可以在之后相同的请求重复使用这个数据。

好处非常明显:消除了一些网络消耗,减少了响应的延迟时间,提高效率,而且数据结果和上次一毛一样,用户感觉不出来。坏处就是:当服务器更新了某些数据,缓存中的数据变成了旧的未更新的数据,数据的可靠性就不能保证了。

4. 支持分层系统

服务器和客户端之间允许有多个不同的中间组件,比如代理层,网关层,缓存组件

举个栗子:客户马总要造汽车,他会找不同供应商合作,车架供应商,玻璃供应商,传感器供应商,轮胎供应商等等。这些供应商可以当作是中间组件。

这样做的好处是什么呢?

① 降低了汽车整车(服务器)的风险,将风险转移给各个供应商。一个人造肯定风险更大,搞不好会因为一个零件问题导致整车造不出来,交付给客户就会延期,客户可能就会爆怒投诉。

② 各个供应商(中间层)都是独立的,不会互相影响。如果有一个供应商出现问题,换掉就是了。

③ 将压力转移给了供应商(中间件),汽车整车(服务器)可以把精力投入到更有价值的事情(可伸缩性)。

缺点是:汽车整车和各个供应商增加了沟通交付环节,也就是说服务器和中间件的交互和数据处理的开销增加了,性能会受影响。

5. 支持按需代码

啥叫按需代码?说白了,就是服务器直接给客户端一段代码让客户端执行。美其名曰,减轻了客户端的工作量,对客户端的功能进行扩展。当然了,给你的代码如果是让你攻击别人,你执行完那就完犊子了(一般不会啦,哈哈)。

简单案例:


使用Spring编写一个REST风格的例子。

  1. 资源是用户(User)
  2. 统一URI,即”/api/v1/user”
  3. 统一接口,使用HTTP的4个方法:GET, POST, PUT, DELETE

服务器代码示例:

/**
 * 用户资源操作类
 * @author 米修哥Coding
 * @version v1.0
**/
@RestController
@RequestMapping(path = "/api/v1/user")
public class UserController {
  @Autowired
  private UserService userService;
  
  /**
   * 根据用户ID查询用户信息
  **/
  @RequestMapping(method = RequestMethod.GET)
  public User getUser(@RequestParam("userId") String userId) {
    User user = userService.queryByUserId(userId);
    // 记录操作日志等...
    return user;
  }
  
  /**
   * 新增用户信息
  **/
  @RequestMapping(method = RequestMethod.POST)
  public String addUser(@RequestBody User user) {
    User user = userService.addUser(user);
    // 记录操作日志等...
    return user.getUserId;
  }
  
  /**
   * 修改用户信息
  **/
  @RequestMapping(method = RequestMethod.PUT)
  public String updateUser(@RequestBody User user) {
    User user = userService.updateUser(user);
    // 记录操作日志等...
    return user.getUserId;
  }
  
  /**
   * 删除用户信息
  **/
  @RequestMapping(method = RequestMethod.DELETE)
  public void deleteUser(@RequestParam("userId") String userId) {
    userService.deleteByUserId(userId);
    // 记录操作日志等...
  }
}

客户端代码示例:

客户端使用Spring Cloud OpenFeign来作为客户端组件,调用服务器端的User资源。


/**
 * 用户客户端操作类
 * @author 米修哥Coding
 * @version v1.0
 */
@FeignClient(name = "user-service", path = "/api/v1/user")
public interface UserClient {
    
  /**
   * 根据用户ID查询用户信息
  **/
  @RequestMapping(method = RequestMethod.GET)
  User getUser(@RequestParam("userId") String userId);
  
  /**
   * 新增用户信息
  **/
  @RequestMapping(method = RequestMethod.POST)
  String addUser(@RequestBody User user);
  
  /**
   * 修改用户信息
  **/
  @RequestMapping(method = RequestMethod.PUT)
  String updateUser(@RequestBody User user);
  
  /**
   * 删除用户信息
  **/
  @RequestMapping(method = RequestMethod.DELETE)
  void deleteUser(@RequestParam("userId") String userId);
}

Rest和Http什么关系?


REST,全称是 Representational State Transfer,中文意为表现层状态转移。它是一种设计风格,而不是标准,主要用于客户端和服务器交互类的软件。RESTful 是实现 REST 设计风格的 web 服务。

HTTP,全称是 HyperText Transfer Protocol,中文意为超文本传输协议。它是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP 是万维网的数据通信的基础。

REST 和 HTTP 的关系在于,REST 通常使用 HTTP 作为其通信协议。REST 通过使用 HTTP 的方法,如 GET、POST、PUT、DELETE 等,来实现资源的获取、创建、修改和删除等操作。这些方法也被称为 CRUD(Create、Read、Update、Delete)操作。

在 RESTful 的设计中,每个 URL 代表一种资源,而通过 HTTP 的方法来操作这些资源。例如,我们可以通过发送 GET 请求到某个 URL 来获取资源,通过 POST 请求来创建新的资源,通过 PUT 请求来更新资源,以及通过 DELETE 请求来删除资源。

同时,RESTful 设计也强调无状态性,即每次请求都应包含处理请求所需的所有信息,而不依赖于之前的请求。这使得 RESTful 服务更易于扩展,并且更适合于互联网的分布式环境。

总的来说,REST 是一种设计风格,而 HTTP 是实现这种设计风格的一种协议。在实际应用中,RESTful web 服务通常使用 HTTP 作为其通信协议,但理论上,也可以使用其他的协议来实现 REST 设计风格。

REST架构对资源的操作包括获取、创建、修改和删除资源的操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法

  • (一) 首先REST只是一种风格,不是一种标准
  • (二) REST是以资源为中心的
  • (三) REST充分利用或者说极端依赖HTTP协议

总结一下:


  1. REST是一种架构风格,面向资源进行操作,用 URI来标记资源。
  2. REST统一了接口、统一了URI;支持无状态;可缓存;支持分层;支持按需代码。

补充:RESTful 是一个形容词,意思是支持或遵循REST架构风格。