接口的幂等性

今天在做一个需求的时候,要求考虑接口的幂等性,后台根据模板生成pdf时,要求只能生成一次,后续请求都只能是查询到生成的pdf。

为什么会出现重复请求?

  • 网络波动:内部调用会存在重试机制,dubbo接口默认有重试机制,服务的restful接口也有重试机制,axios也有重试机制。
  • 用户重复点击:用户点击过快
  • 浏览器:回退操作等都可能导致重复请求

在网络不稳定、客户端重试、用户重复提交等场景下,同一个请求可能被多次发送到服务端。如果没有幂等性保障,可能导致:

  • 重复下单
  • 重复扣款
  • 数据重复插入
  • 状态错误变更

从前端的角度去考虑幂等性

  • 如果是按钮,防止用户点击过快,可以在用户点击后就进入loading状态,不可再使用
  • 如果是表单,提交后跳转,且不允许后退重新提交表单

从后端角度考虑幂等性:能够正确识别出相同的请求,并且合理处理非首次到达的请求。

  • Token机制:

    用户在进入到提交的页面时,自动从后台获取token,然后提交时携带token,然后保证token只能校验一次 Redis实现:进入页面颁发token,发生请求时删除token,删除成功则放行。

    ini 复制代码
    String script = """
        if redis.call('EXISTS', KEYS[1]) == 1 then
            redis.call('DEL', KEYS[1])
            return 1
        else
            return 0
        end
    """;
    ​
    RedisScript<Long> redisScript = RedisScript.of(script, Long.class);
    Long result = redisTemplate.execute(redisScript, Collections.singletonList("my_token"));
    ​
    if (result == 1) {
       // Token 存在并已删除,可以执行业务
    } else {
        // Token 不存在,处理重复请求
    }

    某些场景,可以考虑将这个token交由客户端生成,能够保证客户端安全可控即可,可以直接用现成的setnx命令。

  • 数据库唯一约束:通过接口的请求中一些能够唯一标识请求的数据作为key存放到数据库中 如提前生成订单号,在下单时再真正插入订单数据,用订单号作为数据库的主键。

  • 乐观锁:默认获取锁,执行完逻辑,真正保存数据时再校验是否能成功获取到锁。

    如:update的时候用当前订单状态(初始状态)作为条件。

  • 悲观锁:用redis实现分布式锁,先获取锁再执行逻辑,执行完逻辑后再释放锁。

  • 状态机: 如订单场景:进入通过set status = process where status=initial and order_id=xx,如果update影响条数为1则表明修改状态成功能执行对应逻辑,否则拒绝执行。

相关推荐
肌肉娃子10 小时前
seatunnel-mysqlcdc同步clickhouse方案
后端
阿拉斯攀登10 小时前
SkyWalking使用:Spring Boot场景
spring boot·后端·skywalking
小单于PRO10 小时前
Spring Boot 实现构建一个轻量级地图瓦片服务
java·spring boot·后端
Selegant10 小时前
Spring Boot 3 + Java 21 全新特性实战:虚拟线程、结构化并发与 Record 类型
java·spring boot·后端
何中应10 小时前
【面试题-6】MySQL
数据库·后端·mysql·面试题
woniu_maggie10 小时前
SAP冲销凭证功能
后端
一念之间lq10 小时前
Elpis 第三阶段· 领域模型架构建设
前端·后端
+VX:Fegn089510 小时前
计算机毕业设计|基于springboot + vue旅游信息推荐系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计·旅游
码界奇点11 小时前
基于SpringBoot和Vue的Fuint门店会员营销系统设计与实现
vue.js·spring boot·后端·毕业设计·springboot·源代码管理
用户990450177800911 小时前
ruoyi-vue2集成DMN规则引擎实现Dish出餐决策
后端