RESTful接口设计
1 什么是RESTful
REST全称是Representational State Transfer,中文意思是表述性状态转移。首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。他在论文中提到:”我这篇文章的写作目的,就是想在架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。REST指的是一组架构约束条件和原则。“如果一个架构符合REST的约束条件和原则,我们就称它为RESTful架构。
RESTful架构设计风格,提供了设计原则和约束条件。
2 为什么要是用RESTful请求风格
目前RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。
RESTful是一种设计风格,并非一个标准。因此,即使完全不用这种风格,功能上也能够满足需求。
但是它结构清晰、符合标准、易于理解、扩展方便,越来越多网站在采用它
3 理解RESTful
我们首先需要理解Representational State Transfer这个词组到底是什么意思,它的每一个词都有些什么含义。
结合REST原则,围绕资源展开讨论,从资源的定义、获取、标书、关联、状态变迁等角度,列举一些关键概念并加以解释。
- 资源与URI
- 统一资源接口
- 资源的表述
- 资源的链接
- 状态的转移
3.1 资源与URI
REST全称是表述性状态转移,这里的表述其实指的就是资源。任何事物只要有被引用的必要,它就是一个资源。资源可以是实体,可以是一个抽象的概念。
要让一个资源可以被识别,需要有个唯一标识,在Web中这个唯一的标识就是==URI(统一资源标识符)==(Uniform Resource Identifier)。URI就可以看成资源的地址,也可以看成是资源的名称。如果某些信息没有使用URI表示,那他就不能算是一个资源,只能算是资源的一些信息而已。URI的设计应该遵循可寻址性原则,具有自描述性,需要在形式上给人直觉上的关联。以github网站为例:
- https://github.com/git
- https://github.com/git/git
- https://github.com/git/git/blob/master/block-sha1/sha1.h
- https://github.com/git/git/commit/e3af72cdafab5993d18fae056f87e1d675913d08
- https://github.com/git/git/pulls
- https://github.com/git/git/pulls?state=closed
使用_或-来让URI可读性更好
曾经Web上的URI都是冰冷的数字或者无意义的字符串,但现在越来越多的网站使用_或-来分隔一些单词,让URI看上去更为人性化。 例如国内比较出名的开源中国社区,它上面的新闻地址就采用这种风格, 如http://www.oschina.net/news/38119/oschina-translate-reward-plan。
- 使用/来表示资源的层级关系
例如上述/git/git/commit/e3af72cdafab5993d18fae056f87e1d675913d08就表示了一个多级的资源, 指的是git用户的git项目的某次提交记录,又例如/orders/2012/10可以用来表示2012年10月的订单记录。
- 使用?用来过滤资源
很多人只是把?简单的当做是参数的传递,很容易造成URI过于复杂、难以理解。可以把?用于对资源的过滤, 例如/git/git/pulls用来表示git项目的所有推入请求,而/pulls?state=closed用来表示git项目中已经关闭的推入请求, 这种URL通常对应的是一些特定条件的查询结果或算法运算结果。
- ,或;可以用来表示同级资源的关系
有时候我们需要表示同级资源的关系时,可以使用,或;来进行分割。例如哪天github可以比较某个文件在随意两次提交记录之间的差异,或许可以使用/git/git /block-sha1/sha1.h/compare/e3af72cdafab5993d18fae056f87e1d675913d08;bd63e61bdf38e872d5215c07b264dcc16e4febca作为URI。 不过,现在github是使用…来做这个事情的,例如/git/git/compare/master…next。
3.2 统一资源接口
RESTful架构应该遵循统一接口原则,统一接口包含了一组受限的预定义的操作,不论什么样的资源,都是通过使用相同的接口进行资源的访问。接口应该使用标准的HTTP方法如GET,PUT和POST,并遵循这些方法的语义。REST还要求,对于自愿执行的操作,操作语义必须由HTTP消息体之前的部分完全表述,不能将操作语义冯哲在HTTP消息体内部。
以前
http://127.0.0.1/item/queryItem.action?id=1 (查询,GET)
http://127.0.0.1/item/saveItem.action (新增,POST)
http://127.0.0.1/item/updateItem.action (更新,POST)
http://127.0.0.1/item/deleteItem.action?id=1 (删除,GET或POST)
以下是HTTP方法的典型用法:
GET
- 安全且幂等
- 获取表示
变更时获取表示(缓存)
200(OK) - 表示已在响应中发出
204(无内容) - 资源有空表示
- 301(Moved Permanently) - 资源的URI已被更新
- 303(See Other) - 其他(如,负载均衡)
- 304(not modified)- 资源未更改(缓存)
- 400 (bad request)- 指代坏请求(如,参数错误)
- 404 (not found)- 资源不存在
- 406 (not acceptable)- 服务端不支持所需表示
- 500 (internal server error)- 通用错误响应
- 503 (Service Unavailable)- 服务端当前无法处理请求
POST
- 不安全且不幂等
- 使用服务端管理的(自动产生)的实例号创建资源
- 创建子资源
- 部分更新资源
如果没有被修改,则不过更新资源(乐观锁)
200(OK)- 如果现有资源已被更改
201(created)- 如果新资源被创建
- 202(accepted)- 已接受处理请求但尚未完成(异步处理)
- 301(Moved Permanently)- 资源的URI被更新
- 303(See Other)- 其他(如,负载均衡)
- 400(bad request)- 指代坏请求
- 404 (not found)- 资源不存在
- 406 (not acceptable)- 服务端不支持所需表示
- 409 (conflict)- 通用冲突
- 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
- 415 (unsupported media type)- 接受到的表示不受支持
- 500 (internal server error)- 通用错误响应
- 503 (Service Unavailable)- 服务当前无法处理请求
PUT
- 不安全但幂等
- 用客户端管理的实例号创建一个资源
- 通过替换的方式更新资源
如果未被修改,则更新资源(乐观锁)
200 (OK)- 如果已存在资源被更改
201 (created)- 如果新资源被创建
- 301(Moved Permanently)- 资源的URI已更改
- 303 (See Other)- 其他(如,负载均衡)
- 400 (bad request)- 指代坏请求
- 404 (not found)- 资源不存在
- 406 (not acceptable)- 服务端不支持所需表示
- 409 (conflict)- 通用冲突
- 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
- 415 (unsupported media type)- 接受到的表示不受支持
- 500 (internal server error)- 通用错误响应
- 503 (Service Unavailable)- 服务当前无法处理请求
DELETE
- 不安全但幂等
删除资源
200 (OK)- 资源已被删除
301 (Moved Permanently)- 资源的URI已更改
- 303 (See Other)- 其他,如负载均衡
- 400 (bad request)- 指代坏请求
- 404 (not found)- 资源不存在
- 409 (conflict)- 通用冲突
- 500 (internal server error)- 通用错误响应
- 503 (Service Unavailable)- 服务端当前无法处理请求
3.3 资源的表述
客户端通过HTTP方法可以获取资源,确切地说客户端获取的知识资源的表述而已。资源在外界的具体呈现,可以有多种表述形式,在客户端和服务端之间传送的也是资源的表述,而不是资源本身。例如文本资源可以采用html、xml、json等格式,图片可以使用png或jpg来呈现。
==URI只代表资源的实体,不代表它的形式==,它的具体表现形式应该是HTTP请求头信息中用Accept和Content-Type字段指定。
资源的表述包括数据和描述数据的元数据,例如,HTTP头“Content-Type”就是这样一个元数据属性。
客户端是如何指导服务端提供哪些表述形式?
答案是可以通过HTTP内容协商,客户端可以通过Accept头请求一种特定格式的表述,服务端通过Content-Type告诉客户端资源的表述形式。
4 设计RESTful接口
4.1 资源设计规则
以前的接口:
发布帖子:www.bbc.com/bbs_post?title=xx&content=xxx
修改帖子:www.bbc.com/bbs_update?title=xx&content=xxx
删除帖子:www.bbc.com/bbs_delete?title=xx&content=xxx
这种方式的问题:存在大量的接口方法,URL地址设计复杂
在RESTful架构中,每个网址代表一种资源,所以网址中不能有动词,只能是==名词==,而且所用的名字往往与数据库的表格名对应。一般来说,数据库中的表都是记录同种数据的“集合”(collection),所以URI中的名词也应该使用==复数==。
www.xxx.com/videos
4.2 动作设计规则
| 方法 | 作用 |
|---|---|
| GET(select) | 从服务器取出资源 |
| POST(create) | 在服务器新建一个资源 |
| PUT(update) | 在服务器中更新资源(客户端提供改变后的完整资源),PUT更新整个对象 |
| PATCH(update) | 在服务器更新资源(客户端提供改变的属性【补丁】),PATCH更新个别属性 |
| DELETE(delete) | 从服务器中删除资源 |
动作示例:
GET /videos:列出所有的视频
POST /videos:添加一个视频
GET /videos/id:获取某个视频的信息
PUT /videos/id:更新某个视频的信息(提供该视频的全部信息)
PATCH /videos/id:更新某个视频的信息(提供该视频的部分信息)
DELETE /videos/id:删除某个视频
4.3 返回结果
一个API可以允许返回JSON,XML甚至HTML等文档格式;建议使用JSON
以前通过URL来规定获取的格式类型,比如:
xxx/employee.json;
xxx/employee.html等
但是更建议使用Accpet这个请求头
Accept与Content-Type的区别
Accept属于请求头,Content-Type属于实体头
Http报头分为通用报头,请求报头,响应报头和实体报头
请求方的http报头结构:通用报头|请求报头|实体报头
响应方的http报头结构:通用报头|响应报头|实体报头Accept代表发送端(客户端)希望接受的数据类型
比如:Accept: application/json;
代表客户端希望接受的数据类型是json类型,后台返回json数据
Content-Type代表发送端(客户端|服务器)发送的实体数据的数据类型
比如:Accept: application/json;
代表发送端希望接受的数据类型是json类型,后台就要以json格式来接收前端发过来的数据
两者结合起来:
Accept: application/json;
Content-Type; application/json;
即代表希望接受的数据是json格式,本次请求发送的数据的数据格式也是json
5 Java中常见的RESTful开发框架
- Jersey
- play
- SpringMVC
6 restful风格API使用规则
可以简单理解为restful风格把网址简化了,同一个网址使用不同的请求方法(GET、POST、PUT、DELETE)获得不同的数据,相比传统的接口设计更加简便。根据项目的需求,可以按照这样的规则进行设计,方便之后前后端的联调。
URI链接中使用名词复数
如果存在文章方面的功能需求
不要使用:
www.ccnnaa.com/getAllArticle
www.ccnnaa.com/createArticle
建议使用:
www.ccnnaa.com/articles
子资源表达关系
GET /article/124598 返回id为123598的文章
方法使用规则
| 方法 | 作用 |
| ——————— | —— |
| GET(select) | 查 |
| POST(create) | 新建 |
| PUT(update) | 修改 |
| DELETE(delete) | 删除 |