首页 > 其他分享 >接口幂等性

接口幂等性

时间:2023-06-05 23:32:12浏览次数:27  
标签:令牌 删除 token 接口 Token 提交

任意多次执行所产生的影响均与一次执行的影响相同,这是幂等性的核心特点。其实在我们编程中主要操作就是CURD,其中读取(Retrieve)操作和删除(Delete)操作是天然幂等的,受影响的就是创建(Create)、更新(Update)

一、接口幂等性概念

接口调用存在的问题#

现如今我们的系统大多拆分为分布式SOA,或者微服务,一套系统中包含了多个子系统服务,而一个子系统服务往往会去调用另一个服务,而服务调用服务无非就是使用RPC通信或者restful,既然是通信,那么就有可能在服务器处理完毕后返回结果的时候挂掉,这个时候用户端发现很久没有反应,那么就会多次点击按钮,这样请求有多次,那么处理数据的结果是否要统一呢?那是肯定的!尤其在支付场景。

什么是接口幂等性#

接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条,这就没有保证接口的幂等性。

什么情况下需要保证接口的幂等性#

在增删改查4个操作中,尤为注意就是增加或者修改, A: 查询操作 查询对于结果是不会有改变的,查询一次和查询多次,在数据不变的情况下,查询结果是一样的。select是天然的幂等操作 B: 删除操作 删除一次和多次删除都是把数据删除。(注意可能返回结果不一样,删除的数据不存在,返回0,删除的数据多条,返回结果多个,在不考虑返回结果的情况下,删除操作也是具有幂等性的) C: 更新操作 修改在大多场景下结果一样,但是如果是增量修改是需要保证幂等性的,如下例子: 把表中id为XXX的记录的A字段值设置为1,这种操作不管执行多少次都是幂等的 把表中id为XXX的记录的A字段值增加1,这种操作就不是幂等的 D: 新增操作 增加在重复提交的场景下会出现幂等性问题,如以上的支付问题

二、那些情况需要防止

对于业务中需要考虑幂等性的地方一般都是接口的重复请求,重复请求是指同一个请求因为某些原因被多次提交。导致这个情况会有几种场景:

  • 前端重复提交:提交订单,用户快速重复点击多次,造成后端生成多个内容重复的订单。
  • 接口超时重试:对于给第三方调用的接口,为了防止网络抖动或其他原因造成请求丢失,这样的接口一般都会设计成超时重试多次。
  • 消息重复消费:MQ消息中间件,消息重复消费。
  • 用户页面回退再次提交
  • 微服务互相调用:由于网络问题,导致请求失败。feign触发重试机制
  • 其他业务情况 对于一些业务场景影响比较大的,接口的幂等性是个必须要考虑的问题,例如金钱的交易方面的接口。否则一个错误的、考虑不周的接口可能会给公司带来巨额的金钱损失,那么背锅的肯定是程序员自己了。

三、幂等解决方案

Token机制#

1、服务端提供了发送Token的接口。我们在分析业务的时候,哪些业务是存在幂等问题的,就必须在执行业务前,先去获取Token,服务器会把Token保存到redis中。 2、然后调用业务接口请求时,把token携带过去,一般放在请求头部。 3、服务器判断token是否存在redis中,存在表示第一次请求,然后删除token,继续执行业务。

各种锁机制#

1、数据库悲观锁# select * from xxx where id = 1 for update; 悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,需要根据实际情况选用。另外注意的是,id字段一定是主键或唯一索引,不然可能造成锁表的结果,处理起来非常麻烦。

2、数据库乐观锁# 这种方法适合在更新的场景中:

update t_goods set count = count-1,version=version+1 where good_id=2 and version = 1 根据version版本,也就是在操作库存前先获取当前商品的version版本号,然后操作的时候带史昂此version版本。 乐观锁主要使用于处理读多写少的问题。

业务层分布式锁#

如果多个机器可能在同一时间处理相同的数据,比如多台机器定时任务都拿到了相同的数据处理,我们就可以加分布式锁,锁定此数据,处理完成后释放锁。获取到锁的必须先判断这个数据是否被处理过。

四、项目实战

为了防止订单重复提交,所以,我们使用Token令牌来做幂等性处理。 image.png

订单确认页生成token

// 防重令牌(防止表单重复提交)
//给服务器 token 令牌 KEY oreder:token+用户id value是 token 时间30分钟
String token = UUID.randomUUID().toString().replace("-", "");
redisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX+memberResponseVo.getId(), token,30, TimeUnit.MINUTES);
//也给页面一个 token 令牌
confirmVo.setOrderToken(token)
//前端页面将该Token设置为隐藏域,订单确认提交的时候,该Token会携带上。
 <input name="orderToken" th:value="${confirmOrderData.orderToken}" type="hidden"/>
//完整	
<form action="http://order.gulimall.com/submitOrder" method="post">
	<input id="addrInput" type="hidden" name="addrId" />
	<input id="payPriceInput" type="hidden" name="payPrice">
	<input name="orderToken" th:value="${orderConfirmData.orderToken}" type="hidden"/>
	<button class="tijiao" type="submit">提交订单</button>
</form>

原子令牌

在处理提交上来的订单时,一定要通过lua脚本原子验证令牌和删除令牌机制,否则还会有漏洞。如果快速点击了两下提交按钮,这时两个请求几乎同时进来,第一个先去查询redis,然后再准备删除token的时候,第二个也查了redis,存在Token,这样还是会造成重复提交。如果使用原子验证令牌,就可以完美解决该问题。

//1、验证令牌是否合法【令牌的对比和删除必须保证原子性】
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
String orderToken = vo.getOrderToken();

//通过lua脚本原子验证令牌和删除令牌
//execute 执行脚本 传入DefaultRedisScript 返回是0【校验令牌失败】和1【校验令牌成功】
Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
     Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberResponseVo.getId()),
     orderToken);
if (result == 0L) {
          //令牌验证失败
      } else {
          //令牌验证成功
      }

标签:令牌,删除,token,接口,Token,提交
From: https://blog.51cto.com/u_15993308/6420697

相关文章

  • C#中抽象类和接口的区别与使用
    抽象类是特殊的类,只是不能被实例化;除此以外,具有类的其他特性;重要的是抽象类可以包括抽象方法,这是普通类所不能的。抽象方法只能声明于抽象类中,且不包含任何实现,派生类必须覆盖它们。 一、抽象类: 抽象类是特殊的类,只是不能被实例化;除此以外,具有类的其他特性;重要的是抽象......
  • 获取电商平台数据采集的方式|api接口|获取商品详情接口(可高并发)
    ​电商平台数据采集是指从电商平台获取各种商品、用户、订单等信息的过程。下面介绍几种常用的获取电商平台数据的方式:1.爬虫:通过爬虫技术可以直接从电商平台的网站上获取数据,包括商品的名称、价格、销量、评论等信息。但是,使用爬虫技术采集数据需要具备一定的技能,并且需要防止......
  • python requests请post接口200,打印提示Unexpected character encountered while parsi
    pythonrequests发起httppost请求,带参数,带请求头,代码设置检查没有问题runpy文件提示Unexpectedcharacterencounteredwhileparsingvalue:p.Path,问题一:body请求形式未进行json格式data=json.dumps(body)dumps的功能是将字典类型转换未json格式的字符串类型。......
  • API接口获取快手商品详情(封装代码)
    快手是中国最大的短视频平台之一,也是许多电商企业进行推广的重要渠道。为了更好地了解快手的商品信息,我们可以通过API接口来获取商品详情。首先,我们需要了解快手API接口和相应的文档接下来,我们需要准备请求接口的工具。在这里,我要介绍Python语言和requests库。requests是一个很......
  • 电商平台通过API接口进行数据采集的意义
    电商平台数据采集是指通过一系列的数据收集技术和方法,从电商平台上获取各种与电商活动相关的数据,并进行组织、整合、分析和利用的过程。电商平台数据采集可以获取与以下方面相关的数据:1.商品信息:包括商品名称、描述、价格、运费、库存等数据。2.订单信息:包括订单编号、下单时间、订......
  • 接口和抽象类有什么区别?
    接口(Interface)和抽象类(AbstractClass)是面向对象编程中的两个重要概念,它们之间有以下几个区别:实现方式:接口是一种纯粹的抽象定义,它只包含方法的声明而没有具体的实现。抽象类可以包含具体的方法实现,即可以提供方法的具体实现逻辑。继承关系:类通过关键字"extends"来继承抽象类,可以继......
  • 接口自动化测试
    一、安装python环境1.前往Python官网(https://www.python.org/downloads/windows/)下载Python安装程序。请注意,下载时需要选择与您的操作系统和计算机架构相对应的版本。2.运行下载的安装程序并按照提示进行安装。在安装过程中,请注意选择要安装的组件。通常情况下,您应该选择......
  • 【电商api接口京东系列】获取推荐商品列表+获得商品评论演示示例
    数据采集是指获取和整理各种数据的过程,这些数据可以来自各种来源,例如互联网、社交媒体、传统媒体、设备传感器、企业内部系统等。通常,数据采集是企业或组织重要的商业活动之一。它可以帮助企业了解客户需求、产品趋势、市场机会,以及竞争对手的情况,进而做出更加明智的商业决策。......
  • 电商平台通过API接口进行数据采集的意义
    ​    电商平台数据采集是指通过一系列的数据收集技术和方法,从电商平台上获取各种与电商活动相关的数据,并进行组织、整合、分析和利用的过程。电商平台数据采集可以获取与以下方面相关的数据: 1.商品信息:包括商品名称、描述、价格、运费、库存等数据。2.订单信息:包......
  • 接口测试测什么?
    1. 针对输入参数来测试当成表单来设计测试用例采用等价类,边界值,输入域等方法来设计即: 参数值: 考虑输入合法的数据.非法的数据.考虑边界值. 考虑特殊值, 考虑极限值等等.2. 补充测试a. 测试接口地址测试接口地址不......