Rest风格设计
一.概述
REST是一种表述网络架构的方式。
要理解什么是REST,我们需要理解下面几个概念(引用参考https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/08.3.md)
• 资源(Resources)
REST是"表现层状态转化",其实它省略了主语。"表现层"其实指的是"资源"的"表现层"。那么什么是资源呢?就是我们平常上网访问的一张图片、一个文档、一个视频等。这些资源我们通过URI来定位,也就是一个URI表示一个资源。
• 表现层(Representation)
资源是做一个具体的实体信息,他可以有多种的展现方式。而把实体展现出来就是表现层,例如一个txt文本信息,他可以输出成html、json、xml等格式,一个图片他可以jpg、png等方式展现,这个就是表现层的意思。
URI确定一个资源,但是如何确定它的具体表现形式呢?应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。
• 状态转化(State Transfer)
访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,肯定涉及到数据和状态的变化。而HTTP协议是无状态的,那么这些状态肯定保存在服务器端,所以如果客户端想要通知服务器端改变数据和状态的变化,肯定要通过某种方式来通知它。
Rest架构的规则如下:
规则1:提供资源的接触
在典型的计算机系统中,客户端和服务端的交换命令有“做这个”、 “做那个”等。假如我们想要凭借非REST的方式建立一个要做的事情的列表,它可能是如下的样子:非REST风格
• /changeTodoList.php?item=35&action=changeTitle&title=new_title
注意这种URL是单纯的一条指令——改变资源,但是其中的“changeTodoList”并不是一种事务也不是一种资源。
在REST架构风格中,服务端仅仅提供资源,而资源是客户端和服务端用来交互的概念性的东西。
REST风格
• /todolists/7/items/35/
以上这条URL并不是什么指令,它仅仅代表一种资源或是一种事务的网络地址。你可以用如上的这个地址操作类似“to-do”这样的列表,而这些操作标准的操作(通用格式的操作,下面会介绍)而不是特定的交互命令。
规则2:表达代表资源
一种资源就是一件事物——我们可以用不同的方式描述这些事物。例如,人们想要看html的网页,浏览器就将html转换成合理的布局渲染。但是有时候,网络的接口不仅被人使用而且被机器使用,它们需要一种不同的风格,例如JSON。
In a non-REST way, different formats have different addresses:
非REST方式,不同的形式有不同的地址。
非REST风格
· browser: /showTodoList.php?format=html
· application: /showTodoList.php?format=json
这个问题就是系统用到不同的风格(浏览器和应用程序使用的是不同的url),而且它们之间是没有办法互相通信的,因为请求资源的url不相同。在REST系统中,地址标识的是事物资源,不是形式,所以所有的系统用的同一个地址指向相同的事物资源。那么它们怎么得到不同的形式的资源能
REST风格
· browser: “I want /todolists/7/, please give meHTML.”
· application: “I want /todolists/7/, please give meJSON.”
这种方式使用的是内容协商机制
规则3:交换自描述信息
非REST
1. /search-results?q=todo
2. /search-results?page=2
3. /search-results?page=3
REST
1. /search-results?q=to-do
2. /search-results?q=todo&page=2
3. /search-results?q=todo&page=3
规则4: 资源链接
非 REST
· /todolists/7/
1. {
2. "name":"My to-dos",
3. "items":[35,36]
4. }
REST
· /todolists/7/
1. {
2. "name":"My to-dos",
3. "items":["/todolists/7/items/35/","/todolists/7/items/36/"]
4. }
二.具体实现
本节的采用Spring boot微服务框架实现
l GET
1. 特点
安全性和幂等性
2. 基于属性查询
形式:http:ip/[资源]s/[属性1=]&[属性2=]
举例:http://www.xxx.com/books?publish=xinhua&pageSize=20&pageNum=1
返回形式:list
代码实现
@RequestMapping(value = "", method = RequestMethod.GET)
|
n 以上代码
3. 基于个体查询
形式:http:ip/[资源]s/[id]
举例:http://www.xxx.com/students/1002
代码实现
@RequestMapping(value = "/{id}", method = RequestMethod.GET) public Book getBook( @PathVariable("id") String id) { Book book = new Book("Rest", 58.5, "10001423", "机械工业出版社"); return book; } |
4. 基于个体的属性查询
形式:http:ip/[资源]s/[id]/[attr1]
举例:http://www.xxx.com/students/1002/age
返回结果: 19
举例:http://www.xxx.com/students/1002/name
返回结果: 小明
代码实现:
@RequestMapping(value = "/{id}/{attr}", method = RequestMethod.GET) public String getBookAttr( @PathVariable("id") String id, @PathVariable("attr") String attr) { Book book = new Book("Rest", 58.5, "10001423", "机械工业出版社"); Field[] fields = book.getClass().getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fields[i].setAccessible(true); Field field = fields[i]; String fieldName = field.getName(); if(fieldName.toLowerCase().equals(attr.toLowerCase())) { try{ Object obj = field.get(book); return obj.toString(); }catch (Exception ex){ } } } return null; } |
5. 基于集合的属性的查询(以count为例)
形式:http:ip/[资源]s/count/[属性1=]&[属性2=]
举例:http://www.xxx.com/books/count?press=xinhua
返回结果:133
代码实现:
@RequestMapping(value = "/count", method = RequestMethod.GET) public Integer getBooksAttr( @RequestParam(value = "press", defaultValue="") String press) { return 20; } |
6. 基于jquery前端调用示范
代码实现:
$.ajax({ type: "GET", url: "http://localhost:8085/products/books", success: function (data) { console.log(data); // Play with returned data in JSON format }, error: function (msg) { console.log(msg); } }); |
6.总结
l PUT
1. 特点
数据添加或更新
安全性和幂等性
2. 基于个体添加
形式:http:ip/[资源]s/[id]
举例:
PUT: http://www.xxx.com/students/1002
Data: {
name: “李晓明”,
age: 25,
password:“xxxxxxx”,
userId:“lixiaoming”
}
l DELETE
1. 特点
安全性和幂等性
2. 基于个体删除
形式:http:ip/[资源]s/[id]
举例:
DELETE: http://www.xxx.com/students/1002
l POST
l 安全
l 几种全局GET
l 注意事项
1. 路径范围的无歧义性
客观范围
目标范围
2. 映射函数先后顺序