• REST 是 Representational State Transfer的缩写,如果一个架构符合REST原则,就称它为RESTful架构。

  • RESTful 架构可以充分的利用 HTTP 协议的各种功能,是 HTTP 协议的最佳实践。

  • RESTful API 是一种软件架构风格、设计风格,可以让软件更加清晰,更简洁,更有层次,可维护性更好。

首先:

  • REST只是一种风格,不是一种标准

  • REST是以资源为中心的

  • REST充分利用或者说极端依赖HTTP协议

我们在 Web 应用中处理来自客户端的请求时,通常只考虑 GET 和 POST 这两种 HTTP 请求方法。实际上,HTTP 还有 HEAD、PUT、DELETE 等请求方法。而在 REST 架构中,用不同的 HTTP 请求方法来处理对资源的 CRUD(创建、读取、更新和删除)操作: 若要在服务器上创建资源,应该使用 POST 方法。 若要检索某个资源,应该使用 GET 方法。 若要更改资源状态或对其进行更新,应该使用 PUT 方法。 若要删除某个资源,应该使用 DELETE 方法。

特点:

资源和表示

RESTful系统的核心构建块是资源,资源可以是网页、视频流、图像等。资源甚至可以是抽象的概念,如数据中用户的列表或特定位置的天气预报。唯一真正的限制是系统中的每个资源都是唯一且可标识的。

另外,资源可能有很多种表示形式,在C/S(客户端/服务器)架构中,服务负责管理资源的状态,但是客户端可以选择他们自己希望与之交互的表示方式。

统一接口

统一接口是RESTful系统独特的属性之一,它要求客户端使用同一套标准操作来访问所有的资源。

统一接口的好处在于易于创建与其提供的服务脱钩的实现,这使得服务可以在不影响客户端的情况下发展。需要权衡的是,统一的接口可能会对某些系统增加了不必要的限制,或要求服务器执行的效率低于专门操作的效率,如果Spring Cloud的服务调用是没有Dubbo的效率高。

无状态

RESTful系统中,所有的操作都应该是无状态的。这意味着从客户端到服务器的每个调用都不得依赖任何的共享状态,不仅本次请求要包含处理所需要的所有信息,且服务端不能存储来自客户请求中的信息并用户客户的下一个请求中

REST中的无状态要求让位于几个关键属性:

  • 可见性:可以单独分析每个请求,以监视系统运行状况和响应速度

  • 可靠性:系统故障时,更容易从中恢复

  • 可拓展性:简单地添加更多的服务器资源以处理更多的请求

路径规则|域名

路径又称 “终点”(endpoint),表示 API 的具体网址。

在 RESTful 架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的 “集合”(collection),所以 API 中的名词也应该使用复数。

包含两种形式:

a、主域名:https://api.example.com

b、子目录:https://example.org/api/

版本控制

版本号:v {n} n 代表版本号,分为整形和浮点型

整型:大功能版本发布形式;具有当前版本状态下的所有 API 接口,例如:v1,v2。

浮点型:为小版本号,只具备补充 api 的功能,其他 api 都默认调用对应大版本号的 api 例如:v1.1 v2.2。

放入位置:

1、将版本号放入URL中(方便直观)。https://api.example.com/v2.2

  1. 将版本号放在请求头。

请求类型

GET(SELECT):从服务器取出资源(一项或多项)。

POST(CREATE):在服务器新建一个资源。

PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。

PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。

DELETE(DELETE):从服务器删除资源。

HEAD:获取资源的元数据;

OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序(sequence、order)。
?producy_type=1:指定筛选条件

地址栏参数

主要用于过滤查询

a、restful 地址栏参数 /api/v1/product/122 122 为产品编号,获取产品为 122 的信息

b、get 方式的查询字串,此种方式主要用于过滤查询,如下:

REST风格与HTTP风格对比

左边是我们自己写的,并且可能有很多返回值.
操作成功 或者1
操作失败 或者0

https://localhost:8080/myweb/getDogs --> GET /rest/api/dogs 获取所有小狗狗 
https://localhost:8080/myweb/addDogs --> POST /rest/api/dogs 添加一个小狗狗 
https://localhost:8080/myweb/updateDogs/:dog_id --> PUT /rest/api/dogs/:dog_id 修改一个小狗狗 
https://localhost:8080/myweb/deleteDogs/:dog_id --> DELETE /rest/api/dogs/:dog_id 删除一个小狗狗

REST风格的返回比较固定.

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxx
 
{
   "url" : "/api/categories/1",
   "label" : "Food",
   "items_url" : "/api/items?category=1",
   "brands" : [
         {
            "label" : "友臣",
            "brand_key" : "32073",
            "url" : "/api/brands/32073"
         }, {
            "label" : "乐事",
            "brand_key" : "56632",
            "url" : "/api/brands/56632"
         }
         ...
   ]
}

//格式固定,第一行是操作状态
//第二行是返回值类型
//第三行是内容长度
//第五行开始是内容
//传统的需要访问和服务方协商和做不同的解析程序,REST风格就可以保持统一
//示例
//1、获取文章

请求:
GET /blog/post/{postId} HTTP/1.1

响应:
HTTP/1.1 200 OK
{
    "title": "foobar",
    "content": "foobar",
    "comments": ["", "", ""]
}

//2、发布文章

请求:
POST /blog/post HTTP/1.1
{
    "title": "foobar",
    "content": "foobar",
    "comments": ["", "", ""]
}

响应:
HTTP/1.1 201 CREATED
//接口示例
DELETE http://api.qc.com/v1/friends: 删除某人的好友 (在http parameter指定好友id)
POST http://api.qc.com/v1/friends: 添加好友UPDATE 
http://api.qc.com/v1/profile: 更新个人资料

通常定义API路径时不再需要注重哪种操作类型.比如:

左边是错误的,右边是正确的.

GET /rest/api/getDogs --> GET /rest/api/dogs 获取所有小狗狗 
GET /rest/api/addDogs --> POST /rest/api/dogs 添加一个小狗狗 
GET /rest/api/editDogs/:dog_id --> PUT /rest/api/dogs/:dog_id 修改一个小狗狗 
GET /rest/api/deleteDogs/:dog_id --> DELETE /rest/api/dogs/:dog_id 删除一个小狗狗

REST是基于HTTP的请求风格,很好的利用了HTTP的一些特征,如HTTP动词,HTTP状态码,HTTP报文头.

RPC 与 REST

同事跟你讲RPC与REST的时候,他心里想的应该是“API设计风格”。这样讲没错,但是不准确。我们先来看这两种“API设计风格”有什么区别:

如果我开了一个小餐馆,想设计一个订餐的API:

两种风格的API区别,总结一下其实非常简单:

  • RPC面向过程,只发送 GET 和 POST 请求。GET用来查询信息,其他情况下一律用POST。请求参数是动词,直接描述动作本身。

  • RESTful面向资源,使用 POST、DELETE、PUT、GET 请求,分别对应增、删、改、查操作。请求参数是名词,这个名词就是“增删改查”想要操作的对象。

前面提到,这样对比RPC与REST并不完全准确,原因在于RPC不仅仅是一种API设计风格,它的概念比这要广得多。

PRC全称是Remote Procedure Call,即远程过程调用。我发送了一个RPC请求比如 POST /removeItem?itemId=456,实际上是调用了远程服务端的一个方法 removeItem(int itemId)。在我本地电脑上可以调用一个远在服务端的方法,所以叫远程过程调用。这个"远"的概念也不一定是跨越网络的,同一台主机的两个进程之间相互交流也完全可以是RPC。

PRC一般带有服务治理,请求熔断等特点.

PUT 和 POST 的区别主要在以下几个方面:

  1. 语义不同:PUT 请求通常用于更新或替换服务器上的资源,而 POST 请求通常用于创建新的资源或提交数据到服务器进行处理。

  2. 客户端发送的数据不同:PUT 请求需要客户端发送完整的资源内容,而 POST 请求可以只发送部分资源内容。

  3. 响应不同:PUT 请求成功后通常返回 200 OK 状态码,而 POST 请求成功后通常返回 201 Created 状态码,并返回表示新资源的 URI。

  4. 幂等性不同:PUT 请求具有幂等性,即执行多次 PUT 请求的结果应该相同,而 POST 请求不具有幂等性。

SpringBoot中示例

常用的四中请求

全部查询:@GetMapping("/list")

@GetMapping("/list") 等于 @RequestMapping("/list")

 //@RequestMapping("/list")
    @GetMapping("/list")
    public List<Account> list(){
        return accountService.findAccountList();
    }

单个查询:@GetMapping("/getOne/{id}")

@GetMapping("/getOne/{id}") 等于 @RequestMapping(value = “/getOne/{id}”,method = RequestMethod.GET)

//@RequestMapping(value = "/getOne/{id}",method = RequestMethod.GET)
    @GetMapping("/getOne/{id}")
    public  Account getAccountById(@PathVariable("id")int id){
        return accountService.findAccountById(id);
    }

新增:@PostMapping(value = “/add”)

@PostMapping(value = “/add”) 等于
@RequestMapping(value = “/add”, method = RequestMethod.POST)

/**
     *
     * 新增,用POST
     */
    //@RequestMapping(value = "/add", method = RequestMethod.POST)
    @PostMapping(value = "/add")
    public String postAccount(@RequestParam(value = "name") String name,
                              @RequestParam(value = "money") double money) {
        Account account = new Account();
        account.setMoney(money);
        account.setName(name);
        accountService.add(account);
        return account.toString();

    }

更新:@PutMapping( “/update/{id}”)

@PutMapping( “/update/{id}”)等于
@RequestMapping(value = “/update/{id}”,method = RequestMethod.PUT)

/**
     * 更新,用PUT
     */
    //@RequestMapping(value = "/update/{id}",method = RequestMethod.PUT)
    @PutMapping( "/update/{id}")
    public String updateAccount(@PathVariable("id") int id,
                                @RequestParam(value = "name") String name,
                                @RequestParam(value = "money") double money

    ){
        //System.out.println("-----------11111111");
        Account account = new Account();
        account.setMoney(money);
        account.setName(name);
        account.setId(id);
        accountService.update(account);
        //System.out.println("--------111------------");
        return account.toString();

    }

删除: @DeleteMapping("/delete/{id}")

@DeleteMapping("/delete/{id}")等于
@RequestMapping(value = “/delete/{id}”, method = RequestMethod.DELETE)

@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
    @DeleteMapping("/delete/{id}")
    public void deleteAccount(@PathVariable("id") int id){

        accountService.delete(id);
    }

文章作者: 刘同学
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 刘同学的小站
后端 Java
喜欢就支持一下吧