场景#
在电商购物的时候,如果由于网络比较卡,或者其他原因。用户多次点击了支付按钮,结果对同一个商品支付多次。
如果这种场景发生了,那会对电商平台的业务和信誉都产生很大的影响。
有些杠精会说,没关系,因为每次支付会有支付密码的输入,所以多次问题不会发生。那么免密支付怎么办?
曾经有同仁提出,开发退款系统,如果多次支付退款系统就会自动予以退款。看似在技术上解决多次支付的问题,但是对用户心理的影响也是很大的。
但是如果出现用户多次点击退款的按钮,出现多次退款的情形呢?如果使用上面的思路,电商平台开发什么平台予以追回呢?
分析#
这类重复提交的问题,都可以归结为接口不幂等的原因造成的。在http中可知GET方法是幂等的,因为GET代表的是一种读操作;
而以POST为代表的创建就不是幂等的了。
注:写操作不都是非幂等的。例如PUT就是幂等的
对于这类非幂等的接口,怎么优化呢?为了实现高并发,所有的接口基本都是无状态的。后端无法识别一个请求是否重复提交了。
那么如果能判断某个请求是否重复提交了,那么这个问题也就解决了。
方案#
对每个订单统计提交次数进行统计。如果提交次数大于或等于1了,表示已经提交了;如果是0 则表式第一次提交。
我们可以使用redis的incr进行统计。每次请求过来,即对订单的id 进行incr 操作。
1 | 请求1---| 每个请求都会执行 |- if orderID = 1 允许请求 ---> 业务处理 |
此方案可以解决重复提交的问题了,但是会带来一个新问题。
如过一个恶意攻击者,胡乱写一下orderID 然后模拟一个请求呢?如果模拟几千万个呢(实际开中会对一个用户单位时间内的访问次数进行限定)
那么如果恶意攻击者有很多账号呢?
优化方案就是在生成支付订单的时候,直接直接执行set orderID 0 ex seconds
,那么此时redis中orderID 的value就是1。
请求到来的时候,对Redis执行get orderID
如果存在则继续,否则认为是不合法的orderID