如何实现接口的幂等性

1,什么是幂等性

即相同的多次请求,只执行一次。

2,简述怎么保证幂等性?

单机部署的场景
使用唯一标识符:
在客户端发起请求时,附加一个唯一的请求标识符(如 UUID)。服务端接收到请求后,检查这个标识符是否已经处理过。如果已处理过,直接返回之前的结果;否则,处理请求并记录标识符。

分布式部署场景
借用脱离服务自身存储外的第三方工具,如:redis缓存,mysql中的唯一约束,s3存储等都可以

实现方法思路

1,前端

  • 请求去重

    • 使用请求标识符(如UUID)来标识每个请求,确保在短时间内相同请求只发送一次。
    • 在发送请求前,可以将请求记录在内存或缓存中,如果再次发送相同请求,直接返回之前的结果。
  • 限制用户操作

    • 在用户界面中,禁用提交按钮或相应操作,直到请求完成,以防止用户多次点击。
  • 重定向界面
    • 在点击之后,跳转到新的界面(最好是静态界面),防止用户多次点击
  • 处理响应

    • 对于重复请求的响应,应确保前端能够正确处理并显示,比如缓存结果,发现为同一请求时直接返回缓存。

2,后端

  • 唯一请求标识

    • 在接收请求时,检查请求中是否包含唯一标识符。如果已经处理过该请求,返回之前的结果,而不是重新执行操作。如:使用数据库的唯一约束来防止重复插入(如使用唯一索引).
  • 使用幂等的逻辑

    • 确保业务逻辑设计是幂等的,比如更新操作应始终更新到同一状态而不产生副作用。
  • 设计接口时考虑状态

    • 对于状态转换,确保状态之间的转换是幂等的,例如从“待处理”到“已完成”的转换应能多次接受同一请求而不会产生额外副作用。
  • 监控与日志

    • 记录每个请求及其处理结果,以便在需要时可以审计和排查问题。

3,举个栗子

以数据库为例

首先简单创建一张表

CREATE TABLE `roejrtest`.`uq`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `key` varchar(255) NULL,
  `value` varchar(255) NULL,
  `uuid` varchar(200) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `index_uq_uuid`(`uuid`)
);

创建接口进行测试(基础的就不全部展示了),有需要请查看https://blog.youkuaiyun.com/weixin_54925172/article/details/139564046?spm=1001.2014.3001.5501

controller类

package com.luojie.controller;

import com.luojie.controImpl.IdempotenceTestImpl;
import com.luojie.moudle.IdempotenceTestModule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IdempotenceTestController {

    @Autowired
    private IdempotenceTestImpl idempotenceTest;

    @PostMapping("/idempotence/test")
    public void idempotenceTest(@RequestHeader("x-uuid") String uuid, @RequestBody IdempotenceTestModule module) {
        idempotenceTest.setup(uuid, module);
    }
}

实现类

package com.luojie.controImpl;

import com.luojie.dao.mapper2.Mapper2;
import com.luojie.moudle.IdempotenceTestModule;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class IdempotenceTestImpl {

    @Autowired
    private Mapper2 mapper2;

    public void setup(String uuid, IdempotenceTestModule module) {
        // 检查是否已经存在
        String getuuid = mapper2.getuuid(uuid);
        if (StringUtils.isNotBlank(getuuid)) {
            throw new IllegalArgumentException("已经处理过了");
        }
        // 不存在则继续
        module.setUuid(uuid);
        mapper2.insertUq(module);
    }

}

测试,第一次请求时,检查未被拦截

后续请求时,被拦截

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值