回归正题,看过不少RESTful相关的文章总结,参齐不齐,结合工做中的使用,很是有必要概括一下关于RESTful架构方式了,RESTful只是一种架构方式的约束,给出一种约定的标准,彻底严格遵照RESTful标准并非不少,也没有必要。可是在实际运用中,有RESTful标准能够参考,是十分有必要的。javascript
实际上在工做中对api接口规范、命名规则、返回值、受权验证等进行必定的约束,通常的项目api只要易测试、足够安全、风格一致可读性强、没有歧义调用方便我以为已经足够了,接口是给开发人员看的,也不是给普通用户去调用。java
REST:Representational State Transfer(表象层状态转变),若是没据说过REST,你必定觉得是rest这个单词,刚开始我也是这样认为的,后来发现是这三个单词的缩写,即便知道了这三个单词理解起来仍然很是晦涩难懂。如何理解RESTful架构,最好的办法就是深入理解消化Representational State Transfer这三个单词到底意味着什么。linux
1.每个URI表明一种资源;
2.客户端和服务器之间,传递这种资源的某种表现层;
3.客户端经过四个HTTP动词(get、post、put、delete),对服务器端资源进行操做,实现”表现层状态转化”。
android
是由美国计算机科学家Roy Fielding(百度百科没有介绍,真是尴尬了)。Adobe首席科学家、Http协议的首要做者之1、Apache项目联合创始人。git
REST之父Roy Fielding在论文中阐述REST架构的6大原则。github
数据的存储在Server端,Client端只需使用就行。两端完全分离的好处使client端代码的可移植性变强,Server端的拓展性变强。两端单独开发,互不干扰。web
http请求自己就是无状态的,基于C-S架构,客户端的每一次请求带有充分的信息可以让服务端识别。请求所需的一些信息都包含在URL的查询参数、header、body,服务端可以根据请求的各类参数,无需保存客户端的状态,将响应正确返回给客户端。无状态的特征大大提升的服务端的健壮性和可拓展性。json
固然这总无状态性的约束也是有缺点的,客户端的每一次请求都必须带上相同重复的信息肯定本身的身份和状态(这也是必须的),形成传输数据的冗余性,但这种肯定对于性能和使用来讲,几乎是忽略不计的。api
这个才是REST架构的核心,统一的接口对于RESTful服务很是重要。客户端只须要关注实现接口就能够,接口的可读性增强,使用人员方便调用。缓存
服务端返回的数据格式要么是XML,要么是Json(获取数据),或者直接返回状态码,有兴趣的能够看看博客园的开放平台的操做数据的api,post、put、patch都是返回的一个状态码 。
自我描述的信息,每项数据应该是能够自我描述的,方便代码去处理和解析其中的内容。好比经过HTTP返回的数据里面有 [MIME type ]信息,咱们从MIME type里面能够知道数据的具体格式,是图片,视频仍是JSON,客户端经过body内容、查询串参数、请求头和URI(资源名称)来传送状态。服务端经过body内容,响应码和响应头传送状态给客户端。这项技术被称为超媒体(或超文本连接)。
除了上述内容外,HATEOS也意味着,必要的时候连接也可被包含在返回的body(或头部)中,以提供URI来检索对象自己或关联对象。下文将对此进行更详细的阐述。
如请求一条微博信息,服务端响应信息应该包含这条微博相关的其余URL,客户端能够进一步利用这些URL发起请求获取感兴趣的信息,再如分页能够从第一页的返回数据中获取下一页的URT也是基于这个原理。
客户端一般没法代表本身是直接仍是间接与端服务器进行链接,分层时一样要考虑安全策略。
在万维网上,客户端能够缓存页面的响应内容。所以响应都应隐式或显式的定义为可缓存的,若不可缓存则要避免客户端在屡次请求后用旧数据或脏数据来响应。管理得当的缓存会部分地或彻底地除去客户端和服务端之间的交互,进一步改善性能和延展性。
服务端可选择临时给客户端下发一些功能代码让客户端来执行,从而定制和扩展客户端的某些功能。好比服务端能够返回一些 Javascript 代码让客户端执行,去实现某些特定的功能。
提示:REST架构中的设计准则中,只有按需编码为可选项。若是某个服务违反了其余任意一项准则,严格意思上不能称之为RESTful风格。
如github开放平台
https://developer.github.com/v3/
就是将版本放在url,简洁明了,这个只有用了才知道,通常的项目加版本v1,v2,v3?好吧,这个加版本估计只有大公司大项目才会去使用,说出来不怕尴尬,我真没用过。有的会将版本号放在header里面,可是不如url直接了当。
https://example.com/api/v1/
query parameter能够采用驼峰命名法,也能够采用下划线命名的方式,推荐采用下划线命名的方式,听说后者比前者的识别度要高,多是用的人多了吧,因人而异,因团队规范而异吧。
https://example.com/api/users/today_login 获取今天登录的用户 https://example.com/api/users/today_login&sort=login_desc 获取今天登录的用户、登录时间降序排列
API 命名应该采用约定俗成的方式,保持简洁明了。在RESTful架构中,每一个url表明一种资源因此url中不能有动词,只能有名词,而且名词中也应该使用复数。实现者应使用相应的Http动词GET、POST、PUT、PATCH、DELETE、HEAD来操做这些资源便可
不规范的的url,冗余没有意义,形式不固定,不一样的开发者还须要了解文档才能调用。
https://example.com/api/getallUsers GET 获取全部用户 https://example.com/api/getuser/1 GET 获取标识为1用户信息 https://example.com/api/user/delete/1 GET/POST 删除标识为1用户信息 https://example.com/api/updateUser/1 POST 更新标识为1用户信息 https://example.com/api/User/add POST 添加新的用户
规范后的RESTful风格的url,形式固定,可读性强,根据users名词和http动词就能够操做这些资源
https://example.com/api/users GET 获取全部用户信息 https://example.com/api/users/1 GET 获取标识为1用户信息 https://example.com/api/users/1 DELETE 删除标识为1用户信息 https://example.com/api/users/1 Patch 更新标识为1用户部分信息,包含在body中 https://example.com/api/users POST 添加新的用户
对于合法的请求应该统一返回数据格式,这里演示的是json
返回成功的响应json格式
{ "code": 200, "message": "success", "data": { "userName": "123456", "age": 16, "address": "beijing" } }
返回失败的响应json格式
{ "code": 401, "message": "error message", "data": null }
下面这个ApiResult的泛型类是在项目中用到的,拓展性强,使用方便。返回值使用统一的 ApiResult 或 ApiResult
错误返回 使用 ApiResult.Error 进行返回; 成功返回,要求使用 ApiResult.Ok 进行返回
public class ApiResult: ApiResult { public new static ApiResult<T> Error(string message) { return new ApiResult<T> { Code = 1, Message = message, }; } [JsonProperty("data")] public T Data { get; set; } } public class ApiResult { public static ApiResult Error(string message) { return new ApiResult { Code = 1, Message = message, }; } public static ApiResult<T> Ok<T>(T data) { return new ApiResult<T>() { Code = 0, Message = "", Data = data }; } /// <summary> /// 0 是 正常 1 是有错误 /// </summary> [JsonProperty("code")] public int Code { get; set; } [JsonProperty("msg")] public string Message { get; set; } [JsonIgnore] public bool IsSuccess => Code == 0; }
在以前开发的xamarin android博客园客户端的时候,patch、delete、post操做时body响应里面没有任何信息,仅仅只有http status code。HTTP状态码自己就有足够的含义,根据http status code就能够知道删除、添加、修改等是否成功。(ps:有点linux设计的味道哦,没有返回消息就是最好的消息,表示已经成功了)服务段向用户返回这些状态码并非一个强制性的约束。简单点说你能够指定这些状态,可是不是强制的。经常使用HTTP状态码对照表
HTTP状态码也是有规律的
在请求数据时,客户端常常会对数据进行过滤和分页等要求,而这些参数推荐采用HTTP Query Parameter的方式实现
好比设计一个最近登录的全部用户 https://example.com/api/users?recently_login_day=3
搜索用户,并按照注册时间降序 https://example.com/api/users?recently_login_day=3
搜索用户,并按照注册时间升序、活跃度降序 https://example.com/api/users?q=key&sort=create_title_asc,liveness_desc
关于分页,看看博客园开放平台分页获取精华区博文列表 https://api.cnblogs.com/api/blogposts/@picked?pageIndex={pageIndex}&pageSize={pageSize} 返回示例: [ { “Id”: 1, “Title”: “sample string 2”, “Url”: “sample string 3”, “Description”: “sample string 4”, “Author”: “sample string 5”, “BlogApp”: “sample string 6”, “Avatar”: “sample string 7”, “PostDate”: “2017-06-25T20:13:38.892135+08:00”, “ViewCount”: 9, “CommentCount”: 10, “DiggCount”: 11 }, { “Id”: 1, “Title”: “sample string 2”, “Url”: “sample string 3”, “Description”: “sample string 4”, “Author”: “sample string 5”, “BlogApp”: “sample string 6”, “Avatar”: “sample string 7”, “PostDate”: “2017-06-25T20:13:38.892135+08:00”, “ViewCount”: 9, “CommentCount”: 10, “DiggCount”: 11 } ]
这是一个比较头痛的问题,在作单个实体的查询比较容易和规范操做,可是在实际的API并非这么简单而已,这其中经常会设计到多表链接、多条件筛选、排序等。
好比我想查询一个获取在6月份的订单中大于500元的且用户地址是北京,用户年龄在22岁到40岁、购买金额降序排列的订单列表
https://example.com/api/orders?order_month=6&order_amount_greater=500&address_city=北京&sort=order_amount_desc&age_min=22&age_max=40
从这个URL上看,参数众多、调用起来还得一个一个仔细对着,并且API自己很是不容易维护,命名看起来不是很容易,不能太长,也不能太随意。
在.net WebAPI总咱们可使用属性路由,属性路由就是讲路由附加到特定的控制器或操做方法上装饰Controll及其使用[Route]属性定义路由的方法称为属性路由。
这种好处就是能够精准地控制URL,而不是基于约定的路由,简直就是为这种多表查询量身定制似的的。 从webapi 2开发,如今是RESTful API开发中最推荐的路由类型。
咱们能够在Controll中标记Route
[Route(“api/orders/{address}/{month}”)]
Action中的查询参数就只有金额、排序、年龄。减小了查询参数、API的可读性和可维护行加强了。
https://example.com/api/orders/beijing/6?order_amount_greater=500&sort=order_amount_desc&age_min=22&age_max=40
这种属性路由好比在博客园开放的API也有这方面的应用,如获取我的博客随笔列表
请求方式:GET 请求地址:https://api.cnblogs.com/api/blogs/{blogApp}/posts?pageIndex={pageIndex} (ps:blogApp:博客名)