深入理解 RESTful Api 架构
一些常见的误解
不要以为 RESTful Api 就是设计得像便于 SEO 的伪静态,例如一个 Api 的 URL 类似于 http://xxx.com/blog/1 ,我们可以通过浏览器访问该 URL 而读取文章,但是这并不代表着它就是 RESTful Api 。
也不要认为URL 里有 queryString 就不是 RESTful Api ,例如 http://xxx.com/users/?page=10&page_size=30
更不要认为 HTTP + JSON 就是 RESTful ApI 了。
REST 和 HTTP/1.1
Roy Fielding (Apache HTTP 服务器的核心开发者,Apache 软件基金会的合作创始人,HTTP/1.1 协议专家组的负责人)总结了一套理论框架,然后使用这套理论框架中的指导原则,来指导HTTP/1.1协议的设计方向。后来他在其的博士学位论文 Architectural Styles and the Design of Network-based Software Architectures 中更为系统、严谨地阐述了这套理论框架,并且使用这套理论框架推导出了一种新的架构风格,并且为这种架构风格取了一个令人轻松愉快的名字 REST。
想必通过这个你已经明白了 REST 和 HTTP/1.1 的密不可分的关系了吧。HTTP/1.1 的很多特性就是 REST 的特性,比如连接的无状态性。还有后面说的 REST 五大特性都和 HTTP/1.1 协议密不可分。
RESTful Api 与 SOAP Web API 在 URL 形式上的对比
从设计一个删除评论的 api 说起
我们可以这样设计成类似于:
http://mengkang.net/?method=comment.del&id=x ①
http://mengkang.net/comment/del/id/x ②
或者其他形式的 url。
而 RESTful Api 则是:
[DELETE] http://mengkang.net/comments/1 ③
我们对比可以发现①和② URL 中,都有del
的动作指示。
SOAP Web API采用RPC风格,它采用面向功能的架构,所以我们在设计SOAP Web API的时候首相考虑的是应高提供怎样的功能(或者操作)。
而 RESTful Api 是面向资源的架构。是查询、新增、修改、删除,都该资源无关。
所以我们在③ URL 中没有看到del
的关键字,对比②和③最为明显。
进一步认识 RESTful Api
我们知道 URL 全称为“统一资源定位符(Uniform Resource Locator)”,用于描述 Web 资源所在的位置。RESTful Api 是以 HTTP 协议为强烈依托的,将类似于①和②这种以功能为主导的URL风格舍弃,还原 URL 的本质,它的宗旨就是一个 URL 就应该是一个资源,不能包含任何动作。
[POST] http://mengkang.net/users // 新增
[GET] http://mengkang.net/users/1 // 查询
[PATCH] http://mengkang.net/users/1 // 更新
[PUT] http://mengkang.net/users/1 // 覆盖,全部更新
[DELETE] http://mengkang.net/users/1 // 删除
PUT
和PATCH
的功能都可以代表更新,但略有不同,PUT
大多时候表示更新该资源的全部信息,而PATCH
则更新部分信息。
PUT
和POST
又一些功能的重叠,都可以是新建一个资源,POST
时,新建资源的地址是由服务器返回给客户端的。也就是说客户端在发送POST
请求资源之前还无法预知该资源的地址,这在我们的 Api 开发中非常常见,新建一个帖子,新建一条评论,都如此。
而资源的地址是客户端预先知道的情况则比较少。也有人如此设计而使用PUT
,比如需要对 github 上的某人的项目 star ,则可能会设计成:http://github.com/xxx/zhoumengkang/projectname/star 这里把“对这个项目已经点赞过”看成了一个资源,那么就可以用PUT
,因为要删除这个资源时,还是访问这个 URL。
关于这些功能上有交集的地方,可能后面会有一些更加标准的规范或者协议吧。
最后说下HEAD
和OPTIONS
,HEAD
请求的是资源的元数据,比如一张照片,的元数据则可能包含了,照片拍摄的设备,地点,时间等。服务器一般将对应资源的元数据置于响应的报头集合返回给客户端,这样的响应一般不具有主体部分。OPTIONS
则是发送一种“探测”请求以确定针对某个目标地址的请求必须具有怎样的约束(比如应该采用怎样的HTTP方法以及自定义的请求报头),然后根据其约束发送真正的请求。
关于过滤筛选,排序和 token 等 query string 是支持使用,和唯一资源的概念并不冲突。
我所理解的无状态性和唯一资源对 Api Url 的设计指导
举一个实际的例子,用户黑名单的 CURD。我们可是设计成
[GET] /blacklist
[PUT] /blacklist/{id} #把 id 加入到当前授权用户的黑名单中
[DELETE] /blacklist/{id}
REST的五大特性如上的 api 设计中,首先如上的 url 设计中,通过授权码中获取登录用户 uid。则是有状态的了,其次因为所有的用户访问的资源都是同一个地址,这与唯一资源的概念是相违背的。如果是无状态的,那么就与唯一资源的概念相吻合了。(这只是 restful 所建议的,实际是否需要完全遵守视情况而定)
资源(Resource)
资源的表述(Representation)
状态转移(State Transfer)
统一接口(Uniform Interface)
超文本驱动(Hypertext Driven)
资源的概念是 RESTful 里面最重要的一个概念,很容易被我们忽视和误解,所以就重点阐述了这一特性。
而其他特性,我们日常开发应该都是遵守的,就不再展开说了,需要了解的可以看我的这篇笔记 REST的五个特性 。
Server 端代码的基本设计思想
按照 RESTful Api 的规范,严格来说根据endpoint
找到在 server 端映射成一个资源对象,例如通过 http://mengkang.net/users/1 找到UserResource
对象
而在这个对象里对应着该资源支持的 Http 协议的方法。如果一个对象支持7种方式的请求,则类似于:
public class UserResource { private User user; public UserResource() { } public UserResource(int id) {
//从数据查询处该用户的数据
String name = "xxx";
short age = 23;
user = new User(id,name,age);
} /**
* 获取单个用户
* 从 new UserResource(int) 开始
* @return
*/
public User get(){
return user;
} /**
* 覆盖用户的全部信息
* 从 new UserResource(int) 开始
* @return
*/
public boolean put(){
return true;
} /**
* 只更新用户的部分信息
* 从 new UserResource(int) 开始
* @return
*/
public boolean patch(){
return true;
} /**
* 创建一个 UserResource
* @return
*/
public int post(){
return 1;
} /**
* 删除用户
* @return
*/
public boolean delete(){
return true;
} }
假如我们规定 URL 为 http://mengkang.net/user/1/star 表示是访问者对 id 为 1 的这个用户的 star 状态的一个资源。(当前访问者的信息通过 query string 传递 auth token 的形式获取)如果有关注的 api 那么对于该用户的 star 操作则应新建一个UserStarResource
资源对象,因为每个资源最多只有这7中方法,构造方法除外,而不能有其他的相关的动作方法。
public class UserStarResource { public boolean get(){
return true;
} public boolean post(){
return true;
}
public boolean delete(){
return true;
}
}
REST 状态码
理论上来说我们应该以 Http response status code 作为客户端的标准,而不是在 Http body 体里面定义。这样客户端的能够更快速的获取服务端的响应状态码。
但是由于国内某些网络商会劫持状态码非200
的请求,跳转到他们的广告地址。所以大家还是考虑国内的实际情况。
REST 架构风格约束
客户-服务器(Client-Server)通信只能由客户端单方面发起,表现为请求-响应的形式。
无状态(Stateless)通信的会话状态(Session State)应该全部由客户端负责维护。
缓存(Cache)响应内容可以在通信链的某处被缓存,以改善网络效率。
统一接口(Uniform Interface)通信链的组件之间通过统一的接口相互通信,以提高交互的可见性。
分层系统(Layered System)通过限制组件的行为(即,每个组件只能“看到”与其交互的紧邻层),将架构分解为若干等级的层。
文字比较学院派,仔细一想,想必也发现我们实际工作都已经遵守这五条架构风格了。
短短的一篇文章无法涵盖所有内容,这里推荐下 Github Api, 可以作为大家设计 RSETful Api 的最佳范例。
一个基于 netty 的轻量级的 RESTful Api Server https://github.com/zhoumengkang/netty-restful-server
更多更详细的信息可以阅读下面两篇文章
http://www.cnblogs.com/artech/p/restful-web-api-02.html
http://www.infoq.com/cn/articles/understanding-restful-style/
书籍推荐
深入理解 RESTful Api 架构的更多相关文章
- RESTful API 架构解读
RESTful API 架构解读 首先我们还是先介绍下 RESTful api 的来龙去脉. 首先, RESTful (下文都简称 RESTful api 为 RESTful ) 1.RESTful ...
- RESTful api架构设计
阮老师的这两篇文章足够了 理解 RESTful 架构 RESTful API 设计指南
- 理解Restful api的意义
RESTful API 只是API的设计规范或者是一套设计理论. 单就URL和Method这两个点,你可以这样理解: URL 是用来唯一标示一个互联网资源的,而 Method 是用来标识当前请求对该资 ...
- 我是如何根据豆瓣api来理解Restful API设计的
1.什么是REST REST全称是Representational State Transfer,表述状态转移的意思.它是在Roy Fielding博士论文首次提出.REST本身没有创造新的技术.组件 ...
- RESTful API架构和oauth2.0认证机制(概念版)
1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fielding的 ...
- Restful API 架构与设计参考原则
1. 什么是RESTREST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fielding的博 ...
- 理解 RESTful API 设计规范
RESTful是目前最流行的API设计规范,它是用于Web数据接口的设计.从字面可以看出,他是Rest式的接口,所以我们先了解下什么是Rest. REST与技术无关,它代表的是一种软件架构风格,RES ...
- SpringBoot RESTful API 架构风格实践
如果你要问 Spring Boot 做什么最厉害,我想答案就在本章标题 RESTful API 简称 REST API . 本项目源码下载 1 RESTful API 概述 1.1 什么是 RESTf ...
- 理解RESTful API
近日妹子向我求助RESTful API到底是个什么东西.原因是她们公司一个新启动的项目因为RESTful API起了争执.服务端同学坚持要用RESTful API,而前端同学则认为服务端用RESTfu ...
随机推荐
- 基于SOA架构的TDD测试驱动开发模式
以需求用例为基,Case&Coding两条线并行,服务(M)&消费(VC)分离,单元.接口.功能.集成四层质量管理,自动化集成.测试.交付全程支持. 3个大阶段(需求分析阶段.研发准备 ...
- Linux的locale、LC_ALL和LANG
如果你是一个Linux新手,并且刚刚安装了一个新的英文系统但想要设置成中文系统,肯定会接触到上面几个变量,在网上搜索了一系列解决方法,给一些变量赋一下值,再export一下,或者写到配置文件里面,然后 ...
- BZOJ 4196: [Noi2015]软件包管理器 [树链剖分 DFS序]
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1352 Solved: 780[Submit][Stat ...
- mono for android 自定义titleBar Actionbar 顶部导航栏 修改 样式 学习
以前的我是没有做笔记的习惯的,学习了后觉得自己能记住,但是最近发现很多学的东西都忘记了,所有现在一有新的知识,就记下来吧. 最近又做一个mono for android 的项目 这次调整比较大,上次做 ...
- Spring Batch在大型企业中的最佳实践
在大型企业中,由于业务复杂.数据量大.数据格式不同.数据交互格式繁杂,并非所有的操作都能通过交互界面进行处理.而有一些操作需要定期读取大批量的数据,然后进行一系列的后续处理.这样的过程就是" ...
- .NET 基础一步步一幕幕[面向对象前言]
面向对象前言 2017年的第一篇博文,好久不写博文了,赶紧补上,感觉在以前的<.NET 基础一步步一幕幕>系列博客中,简短的小知识点已经介绍的差不多的(PS:如果还有别的基础知识点我没有介 ...
- jquery库和cityselect插 件的省市 级联
/*$(function(){ $("#select_provice").citySelect({ prov:"北京", nodata:"none&q ...
- 前端开发面试题收集(js部分)
1.问:js中"1"+2+"3"+4 运算结果是? 答: js中,字符串和数值相加,得到的还是字符串,这里的结果1234也是字符串. 2.问:4+3+2+&qu ...
- 前端开发面试题收集(css部分)
http://davidshariff.com/quiz/ 做了下这里面前端开发面试的题,发现有些不会,所以在此做个整理以供自己学习,参考,总结. 1.问: CSS属性是否区分大小写? ul { Ma ...
- NotePad++中JSLint的使用
1.第一步下载Notepad++ 2.安装JSLint插件 3.运行JSlint 4.前提是你设置了当前语言或者本身文件就是js 5.JSLint的作用主要就是检查你的JS的规则正确性(至少是绝大部分 ...