REST接口设计

来源:互联网 发布:说唱网络歌曲 编辑:程序博客网 时间:2024/06/05 00:21

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的规范来保证这种统一性。

创建并保存一个博客:

[plain] view plain copy
  1. POST /blog/save  

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

[plain] view plain copy
  1. GET /blog/get/345  
  2. //更新它  
  3. POST /blog/update/345  

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

[plain] view plain copy
  1. GET /blog/get/345/reply/456  

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

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

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

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

[plain] view plain copy
  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又能简化:

[plain] view plain copy
  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。而实现无状态后,我们可以随意增加,减少服务器数量,都不会对当前用户造成影响。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 三菱按动笔摔了一下断墨怎么办 员工工作一星期不到不给工资怎么办 毕业后报到证一直没去报道怎么办 一直做会计助理学不到东西怎么办 玩守望先锋人物模型没刷出来怎么办 不小心点击拔打黑客lD视频怎么办 套得太深散户都不卖庄家怎么办 黑色衣领掉色在白衣服上怎么办 电脑缝纫界下线切的短怎么办 喝完酒第二天恶心想吐怎么办 纸上怎么办画5种标准眉 电脑密码忘了怎么办最简单的方法 宿舍六个人有一个不想安空调怎么办 绝地求生开在了进游戏的页面怎么办 桃树树根有很大一个洞怎么办啊 截掉的枝干一直往下干怎么办 大佛肚竹的叶子都黄了怎么办 大佛肚竹的枝和叶都掉了怎么办 网吧锁屏后但我的页面没关怎么办 不干了公司把我东西扔了怎么办 竹子种了3个月也不发芽是怎么办 盆栽橘子树夏季叶子全掉了怎么办 盆栽藕叶子全干了是怎么办 家里的盆栽竹根部长霉怎么办 浅色衣服被蓝彩笔染上色怎么办 pr导出视频后显示素材丢失怎么办 ps抠下来的图边缘发白怎么办 ps中抠出的图边缘虚不圆滑怎么办 ps的文字工具多了圆框怎么办 苹果6s屏幕锁忘了密码怎么办 网上下载的3d模型渲染很慢怎么办 cad下载完成后出现闪退怎么办 婴儿在肚子里被系带绑到怎么办 我想给外地的朋友送花怎么办 英雄联盟连接不上聊天服务器怎么办 用黄金换玫瑰金后悔了怎么办 劳力士日志系列玫瑰金和黄金怎么办 香菇代进地注水后长满绿毛怎么办 群主给你带了不满意的头衘怎么办 普兰德雪地靴洗变色了怎么办 书被水泡了皱了黏了怎么办