细说RESTful API之幂等性

目录

接口幂等性的含义

幂等性本来是数学中的含义,表达式的是N次变换与1次变换的结果相同。
而RESTFul API中的幂等性是指调用某个方法1次或N次对资源产生的影响结果都是相同的,须要特别注意的是:这里幂等性指的是对资源产生的影响结果,而不是调用HTTP方法的返回结果。
举个例子,RESTFul API中的GET方法是查询资源信息,不会对资源产生影响,因此它是符合幂等性的,可是每次调用GET方法返回的结果有可能不一样(可能资源的某个属性在调用GET方法以前已经被其余方法修改了)。
实际上,在分布式架构中的API幂等性不只仅针对RESTFul接口,而是对全部类型的接口适用,目的是为了确保调用1次或N次接口时对资源的影响结果都是相同的。html

接口符合幂等性有什么用处

接口的幂等性确保了不管调用1次仍是N次对资源的影响都是相同的,这在某些场合下是很是有用的。
举个例子,有这样一个接口方法:pay(long account, int money),该方法用于银行卡扣款支付,参数account为帐户ID,money为须要扣除的钱数。当用户从网页上点击支付按钮时,在该方法的实现逻辑中须要从指定帐户中扣除对应的商品价钱。若是支付操做已经成功执行,可是响应消息由于某种缘由未能及时返回给客户端,这时候给用户的体验是多是未支付成功,若是此时再次点击支付按钮,那么将再一次执行该方法,结果可能会致使用户只买了一件商品却花了双份的钱,这固然是不合理的。整个流程以下图所示:
接口不符合幂等性git

固然,就上述例子的场景,为了不用户重复支付,是能够经过别的方式解决的,好比:分布式事务,或者根据支付状态提示给予用户进行提示等等。
可是,若是引入了分布式事务,那么将带来实现上的复杂性,并且会影响到接口性能;而采起提示信息的方式并不能百分之百确保用户不会重复支付,存在必定的风险。而若是接口符合幂等性,即:对同一个订单不管是执行一次支付仍是屡次支付,在服务端都确保只会扣一次款,那么既不须要引入分布式事务的复杂性,也能从根本上解决重复支付的问题,这也就是接口符合幂等性的价值所在。github

总而言之,接口符合幂等性在能够下降系统实现的复杂性,并能保证资源状态的一致性。跨域

HTTP方法的幂等性与安全性

RESTFul风格的接口设计本质上使用的是HTTP协议方法,所以,RESTFul接口方法的幂等性指的就是HTTP方法的幂等性。
经常使用的HTTP方法有:OPTIONS(获取服务器信息),HEAD(请求资源首部信息),GET(获取资源),POST(建立资源),PUT(更新资源所有信息),PATCH(更新资源部分信息),DELETE(删除资源)。那么,这些HTTP方法的幂等性又是什么样的呢?
除了幂等性以外,HTTP方法的安全性是指不对资源产生修改。
以下是经常使用HTTP方法的幂等性和安全性总结:浏览器

HTTP方法名称 是否幂等 是否安全
OPTIONS Y Y
HEAD Y Y
GET Y Y
PUT Y N
DELETE Y N
POST N N
PATCH N N

从上述表格中能够看出,HTTP方法的幂等性和安全性并非同一个概念,以下是对个各个方法的幂等性和安全性解释:安全

  • OPTIONS方法经常用于获取服务器信息,不会对资源产生影响,也不会对资源进行修改,所以它是幂等的也是安全的;OPTIONS方法最多见的场景是在浏览器的跨域请求中,若是浏览器发起的是一个跨域访问的API(不管是GET方法仍是POST方法),再真正发送业务的GET或POST方法以前会发送一个OPTIONS方法从服务端获取信息,从服务器返回的信息中得知该请求是否支持跨域访问,从而决定下一步是否能成功发送真正的业务请求。
  • HEAD方法用于请求资源的头部信息,不会资源产生影响,也不会对资源进行修改,所以它是幂等的也是安全的。
  • GET方法用于获取资源信息,虽然可能每次返回的结果都不相同,可是GET方法自己不会对资源产生影响,在RESTFul语义里GET方法也不会修改资源,所以它是幂等的,也是安全的。
  • PUT方法在RESTFul语义里表示对资源进行全量更新,所以调用1次或N次的结果都是一致的,因此它是幂等的,但不是安全的。
  • DELETE方法用于删除资源,调用1次或N次的结果都是相同的,所以是幂等的,但不是安全的。
  • POST方法在RESTFul语义里表示新建资源,显然调用1次与调用N次的结果不一样(调用1次新建1个资源,调用N次新建N个资源),所以不是幂等的,同时也不是安全的。
  • PATCH方法在RESTFul语义里表示对资源的局部更新,所以不能保证调用1次与调用N次的结果相同(如:被更新的资源某个属性随着不一样的调用次数在变化),因此不是幂等的,同时也不是安全的。

如何设计符合幂等性的接口

设计幂等性接口的关键在于保证接口不管是被调用1次仍是N次,它对资源所产生的影响都是相同的。
从上述HTTP方法的幂等性总结中能够得知,HTTP协议的POST和PATCH方法都不是幂等性的(可是咱们却常常会在RESTFul接口中使用到它们),那是否就意味中没法将POST和PATCH方法设计为幂等性接口了呢?答案显然是否认的。在上述例子中,能够将订单ID也做为方法参数之一,如:pay(long account, int money, long order),这样在服务端确保一个订单只会被支付一次(订单号是全局惟一的),那么不管该方法被调用1次仍是N次结果都是同样的,也就保证了接口的幂等性。固然,在哪些没有订单号的场景,能够为接口操做生成一个全局惟一的处理号ID,并把该处理号ID做为方法参数之一,这样在服务端确保一个处理号ID只会被执行一次就保证了接口的幂等性。
符合幂等性的接口调用流程描述以下图所示:
接口符合幂等性服务器

写在最后

虽说设计符合幂等性的接口在某些场合能够下降系统的复杂性(如:能够不用引入分布式事务),可是并不是在全部场合的问题都能经过幂等性接口解决,在必要的时候依然须要引入分布式事务处理这样的框架。咱们不要也不能把接口幂等性做为万能的解决办法,可是,咱们在设计接口时尽可能考虑符合幂等性处理是很是有价值的。restful

【参考】
http://blog.720ui.com/2016/restful_idempotent/ 如何理解RESTful的幂等性
https://www.cnblogs.com/weidagang2046/archive/2011/06/04/idempotence.html 理解HTTP幂等性
https://sofish.github.io/restcookbook/http%20methods/idempotency/ RESTful 手册架构

相关文章
相关标签/搜索