【Web安全】接口幂等

我记得在很早之前,我在一篇关于网络http协议post和put的区别的博客中提到,二者区别的其中之一就是幂等性。当时说post请求是非幂等的,put请求时幂等的。那么幂等到底该怎么理解呢?我下面做一些分享,不对的地方欢迎大佬们积极参与讨论。

一、接口幂等

幂等: 关于幂等的定义,其实说白了就是对于同一种行为,我们操作多次的结果和操作一次的结果是相同的。幂等性其实就是数据一致性和事务完整性。
那么对于接口幂等的理解,就是接口可以支持重复调用,并且重复调用时产生的结果是一致的。这对于和支付相关的项目尤为重要,如果支付相关项目的接口不保证幂等性,可能会造成很严重的后果。

支付接口必须要设计幂等性: 如果程序员不小心设计了非幂等的接口做支付操作。那么就有可能出现用户购买商品时进行支付,支付成功后系统做了扣款操作,但此时返回网络异常,当网络恢复后,用户再次点击提交的话,虽然会返回购买成功,但是(非幂等的接口)用户就又会被扣一次款!!发生这样的情况,用户还怎么能放心使用??大家都希望的是同一笔订单只被扣一次款,所以对于支付接口设计幂等性的接口是必要的。

二、保证幂等性

其实有些操作是天然具有幂等性的。比如数据库查询操作是很经典的幂等行为,因为无论你做多少次,它都只能返回一个结果;网络中的get,put,delete也是天然的幂等操作,在多次使用时可以保证只返回唯一的结果。

但对于不是幂等的操作,我们仍然要面对保证其接口具有幂等性的问题。具体操作方法总结有以下几种:

1.数据库保证全局唯一索引

我们可以根据相关业务的操作和内容生成一个全局ID,在每次执行操作前先查找这个全局唯一ID是否存在,来判断这个操作是否已经执行过。如果查找不存在则把全局ID存储到数据库中;如果已存在则表示该方法已经执行直接返回查询结果即可。
那我们就可以使用这个唯一的id来确保,后面重复多次相同的业务操作的处理逻辑和执行效果是一致的。 使用全局唯一ID是保证幂等性的一个通用方案,它可以支持插入、更新、删除业务操作。这个方案很好理解,但是实现起来就比较麻烦,并且有隐患 -->
因为上述保证幂等方案是分成两步的,第②步(查询)依赖第①步(生成)的结果进行操作,无法保证原子性的。在高并发下就会出现下面的情况:第二次请求在第一次请求第②步订单状态还没有修改为‘已支付状态’的情况下到来,导致结果仍然是不是预期的。既然得出了这个结论,解决这个问题也就变得简单:把查询和变更状态操作加锁,将并行操作改为串行操作。

2.乐观锁

乐观锁是说 我们每次更新数据时都认为此次的操作不会造成数据缺失,所以只是在更新数据那一刻锁表,其他时间不锁表。
具体实现是在数据库的表中增加一个字段version(版本号)或者是其他的状态位。在对表进行操作时同时取出数据和标志位version,当要修改数据表时,对version进行判断是否与之前取出的一致,如果一致则修改,如果不一致则不修改。同时最好保证version通过自增存入数据库的。

注意:乐观锁的更新操作,最好是用主键或者唯一索引来更新,这样在操作是只锁定一行,否则更新操作会引起锁表。

3.使用状态机制

我们在设计一个项目的业务时,肯定会涉及到状态机(状态变更图),就是业务单据上面显示的状态,状态会根据不同的情况会发生变更,一般情况是有限的状态机。如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更请求,理论上是不能够变更的,这样的话,就保证了有限状态机的幂等。

4.token令牌

这种方式分成两个阶段:申请token阶段和支付阶段。 第一阶段,在进入到提交订单页面之前,需要订单系统根据用户信息向支付系统发起一次申请token的请求,支付系统将token保存到Redis缓存中,为第二阶段支付使用。 第二阶段,订单系统拿着申请到的token发起支付请求,支付系统会检查Redis中是否存在该token,如果存在,表示第一次发起支付请求,删除缓存中token后开始支付逻辑处理;如果缓存中不存在,表示非法请求。 实际上这里的token是一个信物,支付系统根据token确认操作权限。缺点是需要系统间交互两次,流程较上述方法复杂一些。

5.支付缓存

把订单的支付请求都快速地接下来,一个快速接单的缓冲管道。后续使用异步任务处理管道中的数据,过滤掉重复的待支付订单。优点是同步转异步,高吞吐量。缺点是不能及时地返回支付结果,需要后续监听支付结果的异步返回。

三、总结

幂等与程序是不是分布式高并发还有JavaEE都没有关系。关键是我们的操作是不是幂等的。一个幂等的操作典型如:把编号为5的记录的A字段设置为0这种操作不管执行多少次都是幂等的。一个非幂等的操作典型如:把编号为5的记录的A字段增加1这种操作显然就不是幂等的。要做到幂等性,从接口设计上来说不设计任何非幂等的操作即可。譬如说需求是:当用户点击赞同时,将答案的赞同数量+1。改为:当用户点击赞同时,确保答案赞同表中存在一条记录,用户、答案。赞同数量由答案赞同表统计出来。总之幂等性应该是合格程序员的一个基因,在设计系统时,是首要考虑的问题,尤其是在像支付宝,银行,互联网金融公司等涉及的都是钱的系统,既要高效,数据也要准确,所以不能出现多扣款,多打款等问题,这样会很难处理,用户体验也不好。所以如果你不注意接口幂等的保证,那么公司老大就该对你有意见咯,hahh~

PS:我还是回来了。这知识长时间不用会忘记的,所以呢,记一本好的笔记真是非常必要的啊 ~~

猜你喜欢

转载自blog.csdn.net/ly_6699/article/details/112962446