为什么要用RESTfulRESTful给我最大的感受就是规范,易懂,优雅。一个结构清晰、易于理解的API可以完全省去大量无意义的交流和文档。而现在RESTful越来越流行。在开始介绍RESTfulAPI之前,我们先介绍一下RESTful架构。RESTful架构REST是RepresentationalStateTransfer的缩写。它的意思是“表示层状态转换”。要理解RESTful架构,最好的方法是理解RepresentationalStateTransfer这个短语的含义,以及每个词代表什么。看懂名字就不难理解REST是一种怎样的设计。资源(Resources)REST的名称“表示层状态转换”中,省略了主语。“表现层”其实就是指“Resources”的“表现层”。所谓“资源”就是网络上的一个实体,或者说是网络上的一条特定信息。它可以是一段文字、一张图片、一首歌、一项服务,总之就是一个具体的现实。你可以用一个URI(UniformResourceLocator)来指向它,每个资源对应一个特定的URI。要获取这个资源,只需访问它的URI,这样URI就成了每个资源的地址或唯一标识。所谓“上网”,就是与互联网上的一系列“资源”进行交互,并调用其URI。表示(Representation)“资源”是一个信息实体,它可以有多种外在表现形式。我们具体呈现“资源”的形式称为它的“表示”。例如,文本可以用txt格式、HTML格式、XML格式、JSON格式甚至二进制格式来表达;图片可以用JPG格式或PNG格式表示。URI只表示资源的实体,而不是它的形式。严格来说,有些URL末尾的“.html”后缀是没有必要的,因为这个后缀表示格式,属于“表现层”范畴,URI应该只表示“资源”的位置。它的具体表现形式应该在HTTP请求的头信息中用Accept和Content-Type字段来指定,这是对“表现层”的描述。状态转移(StateTransfer)访问一个网站代表了客户端和服务器之间的一个交互过程。在这个过程中,必然会涉及到数据和状态的变化。Internet通信协议HTTP协议是一种无状态协议。这意味着,所有状态都保存在服务器端。因此,客户端要想对服务器进行操作,就必须通过某种手段使服务器进行“状态转移”(StateTransfer)。而这个转换是基于表现层的,所以是“表现层的状态转换”。客户端使用的方法只能是HTTP协议。具体来说,在HTTP协议中,有四个动词表示操作方式:GET、POST、PUT、DELETE。它们对应四种基本操作:GET用于获取资源,POST用于创建新资源,PUT用于更新资源,DELETE用于删除资源。总结归纳一下什么是RESTful架构:每个URI代表一个资源;在客户端和服务器之间,传递这个资源的某个表现层;客户端通过四个HTTP动词对服务器端资源进行操作,实现“PresentationLayerStateTransition”。RESTfulAPI的设计介绍完RESTful的含义,我们来谈谈RESTfulAPI的设计。如果协议能全站使用HTTPS当然最好。如果不行,请尝试使用HTTPS登录、注册等涉及密码的接口。域名应尽量在专用域名下部署API。例如:https://api.example.com如果确定API很简单,不会再做进一步的扩展,可以考虑放在主域名下。https://example.org/api/versionnumberAPI的版本号与客户端APP的版本号无关。不要让APP将自己提交应用市场时使用的版本号传递给服务器,而是提供类似API版本号的东西,比如v1、v2。版本号连接在URL中。如:api.example.com/v1/users或者在Header中放入:api.xxx.com/usersversion=v1request一般来说,API的外部形式无非就是增删改查(的当然,具体的业务逻辑要复杂得多),查询分为明细和列表,相当于RESTful中的通用模板。例如,设计一个文章的API,最基本的URL是这几种类型:GET/articles:文章列表GET/articles/id:文章详情POST/articles/:创建文章PUT/articles/id:修改文章DELETE/articles/id:删除文章Token和SignAPI需要设计成无状态的,所以客户端每次请求都需要提供有效的Token和Sign,在我看来,它们的目的是:Token用于证明用户请求属于谁,一般是服务器在登录后随机生成一个字符串(UUID)绑定到登录用户,然后返回给客户端。Token的状态维护一般有两种方式:一种是在用户每次操作时延长或重置TOKEN的生命周期(类似缓存机制),另一种是保持Token的生命周期不变,但在同时返回一个用于刷新的Token,当Token过期后,可以刷新而不是重新登录。Sign用于证明请求是合理的,所以一般客户端会将请求参数拼接起来加密为Sign发送给服务端,这样即使抓包对方也只是修改了参数而不能生成对应的签名并会被发送到服务器看穿。当然也可以将时间戳、请求地址和Token混合到Sign中,让Sign也有owner、timeliness和destination。业务参数在RESTful标准中,PUT和PATCH都可以用于修改操作。它们的区别在于PUT需要提交整个对象,而PATCH只需要提交修改后的信息。但是在我看来,在实际应用中没有必要这么麻烦,所以我一直使用PUT,只提交修改后的信息。另一个问题是POSTing创建对象时使用表单提交好还是JSON提交好。其实两者都可以用。在我看来,它们之间的唯一区别是JSON可以更方便地表示更复杂的结构(带有嵌套对象)。另外,无论使用哪一种,请保持一致,不要将两者混用。还有一个建议,最好把过滤、分页、排序相关的信息交给客户端,包括过滤条件、页数或游标、每页页数、排序方式、升序和降序等,这可以使API更加灵活。但是对于过滤条件、排序方式等,并不需要支持所有的方式,只支持目前正在使用的和以后可能会用到的方式,使用字符串枚举来解析,这样能见度更好。例如:search,客户端只提供关键词,具体的搜索字段,搜索方式(前缀,全文,精确)由服务端决定:/users/?query=ScienJusfilter,只需要支持现有的情况:/users/?gender=1pagination:/users/?page=2&pre_page=20响应尽量使用HTTP状态码,常用的有:200:请求成功201:创建修改成功204:删除成功400:参数错误401:无法登录403:Forbidden404:未找到500:系统错误但是有时候仅仅使用HTTP状态码是无法表达清楚错误信息的,所以也可以包裹一层自定义返回码里面,例如:成功时:{"code":100,"msg":"Success","data":{}}{"code":-1000,"msg":"用户名或密码错误"}data是真正需要返回的数据,只有请求成功时才存在,msg只在开发环境使用,并且仅供开发人员识别。客户端逻辑只允许识别code,不允许直接向用户展示msg的内容。如果错误太复杂而无法在一个段落中描述,您还可以添加一个doc字段,其中包含错误文档的链接。返回的数据JSON比XML更直观,更节省流量,所以尽量不要使用XML。创建和修改操作成功后,需要返回资源的所有信息。返回的数据不应与客户端接口强耦合。在设计API时,不要考虑少查询一张关联表或查询/返回少的字段能带来多少性能提升。而且它必须是基于资源的。即使客户端需要在一个页面展示多个资源,也不要在一个界面中全部返回,而是让客户端分别请求多个界面。最好对返回的数据进行加密压缩,尤其是在移动应用中压缩还是比较重要的。更多好文,关注公众号获取
