转自:http://blog.csdn.net/yanical/article/details/7856670

Rest的作者认为计算机发展到现在,最大的成就不是企业应用,而是web,是漫漫无边的互联网web世界。Web能有这么大的成就,它值得我们研究。所以Rest的作者仔细研究了Web,按照Web的世界一些关键特性,提出了我们在实现企业应用的时候应该遵循的一种风格,就是Restful。

Rest风格的API可以给我们很多好处,比如:简洁,统一,性能,可扩展性等等。可惜的是,在实现Rest的时候,总有一些Rest的关键特性没有实现,比如,无状态性,这在我做过的两个项目和我知道的另外一个项目都存在。事实上要实现无状态性在Java里不是那么容易,因为那意味着要把servlet的session抛弃了。除此之外,Rest的一些其他特性在各个项目中实现的也是各有不同。

接下来,我会列出一些我认为的,要实现Rest风格API的关键步骤:

1. 所有东西都是资源(Resource)

所有要给API操作的对象都只能是资源。不管实际上存在的,还是抽象上的。所有资源都会有一个不变的标识(ID),对资源的任何API操作都不应该改变资源的标识。资源和其他资源会有关系,资源与资源的关系通过资源的标识来引用。对资源的操作都应该是完整的,比如获取资源拿到的应该是一个完整的资源对象(根据企业引用特点有些例外,后面会提到)。

事实上,上面的这些完完全全是按照互联网的特性提出来的。互联网中,一个URL就是一个资源;资源的内容就是HTML页面;不管怎么改HTML内容,URL都不会改变;资源之间通过HTML里的连接联系起来;每次获取的时候,获取到的都是完整的HTML内容。

假设有一个博客系统,那么其中的资源可以包括:博主,每个博主都是一个资源;博客,每篇博客都是一个资源,博客和博主之间有联系,通过ID联系起来;每篇博客都会有回复,回复也算是资源,但是它是隶属于博客的,可以认为回复是博客的子资源(你也可以认为博客是博主的子资源,怎么抽象取决于具体的应用,这里不讨论)。

这步通常不难实现,因为这和ORM中的对象概念是类似的,实现上,如果用了hibernate之类的框架,改动也应该很小。

2. 规范对资源的操作,最好只包括CRUD

CRUD指创建(Create),读取(Read), 更新(Update),删除(Delete)

通常对资源的操作只包含CRUD是不可能的,CRUD里甚至连查找的操作的都没有。但这不妨碍我们对Rest的理解,Rest提出的要求是,对资源的操作都应该是统一的,不管是操作哪种类型的资源,API都应该是一致的。这样当调用API的客户端知道某种资源的时候,它不需要去学习对这个资源该怎么操作,因为对所有资源的操作都是一致的,它们都应该支持CRUD操作,以及一些其他操作,比如list(用来查找,或者列出所有资源), merge(部分更新资源,这应该是唯一的不操作资源所有内容的API)。

这和Web也是一样的,HTTP里只有GET,PUT,POST,HEAD等等几个统一的请求(参考:http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)。

要实现简单的几个操作不难,难在这几个简单操作没法支撑整个系统的需求。但是想想吧,互联网也够复杂了吧,还是不是成功了,而且鱼和熊掌不可兼得。有时候服务器端也不一定要实现所有东西,可以把一些逻辑交给客户端去做。比如显示,Rest里显示是完全交给客户端去处理的,服务器只管数据的存储,不管客户端是网页,还是一个手机应用程序,还是另外一个企业应用。各种各样的客户端进来,他们会有各种各样的需求,服务器端不可能一一满足,只能客户端使用统一的API去组合,实现自己的需求。

3. 规范URL的使用

好了,对资源的操作统一了,但是客户端还是要知道怎么触发对资源的某个具体的操作。Rest用URL的规范来保证这种统一性。

创建并保存一个博客:

  1. POST /blog/save

这个请求需要返回博客的保存后的结果,其中包括博客的标识(ID)。 获取一个已经保存的博客,并更新它:

  1. GET /blog/get/345
  2. //更新它
  3. POST /blog/update/345

这个博客的标识是345。获取博客的某个回复:

  1. GET /blog/get/345/reply/456

对待子资源,通常的做法就是和这个例子一样,是一级一级的往下找。我们还可以有其他方法,比如remove用来删除,merge用来部分更新,list用来查找。

有三种方式可以将参数传给API操作:

第一种是通过URL的地址传递,如前面的例子中把标识放在URL里;

第二种是通过URL的参数,比如,对于一个查找请求,可以把查找的过滤条件放在参数里:

  1. GET /blog/list?name=Azure:用InstanceInputEndpoint直接和指定instance通信

第三种是PUT或者POST请求的时候,把内容放在HTTP body里面。这里通常就是博客的内容。

前面我们的例子中有些请求是GET,有些是POST,其实这是有原则的。通常对资源内容没有改变的操作都实用GET,比如获取资源,查找资源;对资源有改变的操作都用POST,比如保存资源。

如果想做的更好,我们应该近一步的使用HTTP的请求方法,直接把HTTP方法和要做的操作映射起来。比如我喜欢认为GET请求就是获取资源(get),PUT方法就是更新整个内容(save,update,我觉得这两个没必要区分),POST方法就是更新部分内容(merge),DELETE方法就是删除资源(remove)。如果这样的话,请求的URL又能简化:

  1. PUT   /blog           //创建保存一个新的博客
  2. GET   /blog/345    //获取博客345内容
  3. PUT   /blog/345    //更新博客345
  4. GET   /blog/345/reply/456     //获取博客345的回复456
  5. POST /blog/345    //更新博客345的部分内容
  6. DELETE /blog/345   //删除博客345

当然对于list操作,这里就没法满足了,还是需要在URL层面上做些区别。

对于merge操作,有很多人认为是不必要的,Rest不应该提供这个API,但是我觉得在某些情况下很有用。比如某个资源对象,它的内容在不断的扩充,怎么让老的客户端在内容扩充后还能继续使用呢? 如果我们要求所有更新请求都必须把所有内容都放在请求的body中,对于客户端来说就不是那么好做了,但是如果我们允许merge请求,客户端可以可以完全忽略新增加的字段,而只把自己知道的字段放在请求内容中即可。

4. 资源的多重表述

这一步我觉得不是必须的。

Rest里,资源的内容通常直接作为一段JSON或者XML返回给客户端。资源多重表述指的是,一个资源应该能够支持根据客户端的请求,返回相应的格式给客户端。服务器应该按照请求HTTP头中的Accept属性决定返回格式。比如对于Ajax请求,Accept头是application/json,服务端返回JSON格式;对于Android请求,Accept头是application/xhtml+xml,服务器返回XML格式。

我觉得这一步不是必须的因为至少从项目前期来说,我们应该都只会支持一种格式。资源的多重表述给我们一种处理多重请求格式的方式,但是我们不需要一开始就支持它。

5. 进一步合理利用HTTP

前面我们已经应用了HTTP的一些东西,比如请求方法,Accept头。事实上我们可以利用更多。

HTTP支持客户端缓存,在HTTP响应里利用Cache-Control,Expires,Last-Modified三个头字段,我们可以让浏览器缓存资源一段时间。Rest也可以利用这些头,告诉客户端在一定时间内不需要再次请求资源。这对提高性能有很大好处。更多HTTP头信息,可以参考http://en.wikipedia.org/wiki/List_of_HTTP_header_fields

Rest的请求会出错,HTTP的请求也会出错。我们可以直接利用HTTP的response code来告诉客户端Rest请求出了什么错误。比如500,告诉客户端,服务器出错了;401告诉客户端需要把安全验证信息附上,需要登录系统;404告诉请求的资源不存在,等等。更多HTTP响应码,可以参考http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html。在实际的业务中,HTTP的那些response code肯定是不能满足所有需求的,适当的在response body中加上更详细的错误信息也是必须的。

还有其他很多,总之能利用上的就利用上,不比再次发明轮子。

6. 实现请求的无状态

Rest是无状态的。Rest的请求之间不应该有依赖,在调用一个请求前,不需要一定要去提前调用另外一个请求。Rest里面不应该有session,特别是Rest请求不应该保存信息在sesssion里,以便在后面的调用中使用。甚至包括安全验证,客户端不应该需要提前登录,然后把权限信息保存在session里,后面的请求用同一个session来调用。

实现无状态的方法就是,把所有信息都包含在当前的请求中,包括验证信息。HTTP是无状态的,HTTP里有一个Authorization头,HTTP的要求是在每次请求的时候都把验证信息放在里面,服务器每次处理请求前都去验证这个信息。为了安全,我们可以提供一个生成token的Rest API,客户端调用这个API生成token(可以附上用户名/密码来生成token)。在后面的所有请求中都把这个token放在Authentication头中。

实现无状态最大的好处是能够方便的扩展服务器,也即scalability。否则的话,我们要么把Session绑定到具体服务器上,要么用一个共享的空间存储Session。而实现无状态后,我们可以随意增加,减少服务器数量,都不会对当前用户造成影响。

RestAPI的实现的更多相关文章

  1. 中国Azure媒体服务RESTAPI的Endpoint

    Amber Zhao  Thu, Feb 26 2015 4:09 AM 由于海外Azure和中国Azure有不同的domain,很多用户在使用媒体服务RESTAPI时,需要指定中国Azure媒体服务 ...

  2. Flask框架搭建REST-API服务

    一.目的 为了能够将测试工具部署成RESTful-API服务,这样就能通过接口的方式提供统一测试工具服务,使用人员就不用构建application而产生的各种环境问题.使用问题. 适合人群:Pytho ...

  3. [svc]简单理解什么是rpc调用?跟restapi有何区别?

    什么是rpc调用 restapi调用方式是对数据的crud. 常见的我们写flash写个api,或者借助django drf写个标准的resetapi,一个url可以借助httpget post pu ...

  4. 调用kylin的restAPI接口构建cube

    调用kylin的restAPI接口构建cube 参考:http://kylin.apache.org/docs/howto/howto_build_cube_with_restapi.html 1. ...

  5. geoserver源码学习与扩展——restAPI访问

    产生这篇文章的想法是在前端通过js调用restAPI时,总是不成功,发送ajax请求时还总是出现类似跨域的问题,后来查找才发现,默认情况下restAPI的访问都需要管理员权限,而通过ajax请求传输用 ...

  6. ryu的RESTAPI简介——我主要用于下发和查看流表

    一.Rest API简介 REST即表述性状态传递(RepreSentational State Transfer),是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性. 表 ...

  7. Rancher + K8S RestApi使用

      1前言 1.1使用的软件及版本 软件 版本号 Rancher 1.6stable Kubernetes 1.8.3 Docker 1.12.6 1.2 Rancher与K8S的RESTAPI差异 ...

  8. Project Server 2016 RestAPI调用测试

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...

  9. restapi(0)- 平台数据维护,写在前面

    在云计算的推动下,软件系统发展趋于平台化.云平台系统一般都是分布式的集群系统,采用大数据技术.在这方面akka提供了比较完整的开发技术支持.我在上一个系列有关CQRS的博客中按照实际应用的要求对akk ...

  10. restapi(1)- 文件上传下载服务

    上次对restapi开了个头,设计了一个包括了身份验证和使用权限的restful服务开发框架.这是一个通用框架,开发人员只要直接往里面加新功能就行了.虽然这次的restapi是围绕着数据库表的CRUD ...

随机推荐

  1. java课后作业2017.10.20

    动手动脑1: public class Test{ public static void main(String args[]) { Foo obj1=new Foo(); }}class Foo{ ...

  2. (转)彻底隐藏Nginx版本号的安全性与方法

    Nginx默认是显示版本号的,如: [root@bkjz ~]# curl -I www.nginx.orgHTTP/1.1 200 OKServer: nginx/0.8.44Date: Tue, ...

  3. 【bzoj1270】[BeijingWc2008]雷涛的小猫 dp

    题目描述   输入 输出 样例输入 样例输出 8 题解 dp 设f[i][j]表示在第i棵树的j高度时最多吃到的柿子数. 那么只有两种可能能够到达这个位置:滑下来.跳下来. 滑下来直接用f[i][j+ ...

  4. 【bzoj4562】[Haoi2016]食物链 拓扑排序+dp

    原文地址:http://www.cnblogs.com/GXZlegend/p/6832118.html 题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题 现在给你n个物种和m条能量流动 ...

  5. Codeforces Round #389 (Div. 2) 752E(二分答案)

    题目大意 可以理解成有n个木板,可以选取木板将其劈成2半(如果长度是奇数,就切成x和x+1),切完之后还可以再切 然后你要把这n个木板切成更多的木板,然后从中选择k个,使得这k个木板的最小长度尽量大 ...

  6. NAT64与DNS64基本原理概述

    NAT64与DNS64基本原理概述 1.NAT64与DNS64背景     在IPv6网络的发展过程中,面临最大的问题应该是IPv6与IPv4的不兼容性,因此无法实现二种不兼容网络之间的互访.为了实现 ...

  7. (poj)Sequence Median

    Description Given a sequence of N nonnegative integers. Let's define the median of such sequence. If ...

  8. 在 Tomcat 中配置 SSL/TLS 以支持 HTTPS

    本件详细介绍了如何通过几个简单步骤在 Tomcat 中配置 SSL/TLS .使用 JDK 生成自签名的证书,最终实现在应用中支持 HTTPS 协议. 生产密钥和证书 Tomcat 目前只能操作 JK ...

  9. mac 安装 visual studio 配置

    前言:今天主要分享的是 Mac 下一款编程软件--Visual Studio,的确,这款软件之前一直是只有 Windows 系统独占的,2017年终于开发了 Mac 版本. 微软这次为 Mac 开发者 ...

  10. C++中的 Round(),floor(),ceil()

     2.1             2.6               -2.1               -2.6floor : 不大于自变量的最大整数             2          ...