我的编程空间,编程开发者的网络收藏夹
学习永远不晚

架构设计 | 接口幂等性原则,防重复提交Token管理

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

架构设计 | 接口幂等性原则,防重复提交Token管理

本文源码:GitHub·点这里 || GitEE·点这里

一、幂等性概念

1、幂等简介

编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。就是说,一次和多次请求某一个资源会产生同样的作用影响。

2、HTTP请求

遵循Http协议的请求,越来越强调Rest请求风格,可以更好的规范和理解接口的设计。

GET:用于获取资源,不应有副作用,所以是幂等的;

POST:用于创建资源,重复提交POST请求可能产生两个不同的资源,有副作用不满足幂等性;

PUT:用于更新操作,重复提交PUT请求只会对其URL中指定的资源有副作用,满足幂等性;

DELETE:用于删除资源,有副作用,但它应该满足幂等性;

HEAD:和GET本质是一样的,但HEAD不含有呈现数据,仅是HTTP头信息,没有副作用,满足幂等性;

OPTIONS:用于获取当前URL所支持的请求方法,满足幂等性;

二、场景业务分析

1、订单支付

架构设计 | 接口幂等性原则,防重复提交Token管理

实际开发中,经常会面对订单支付问题,基本流程如下:

  • 客户端发起订单支付请求 ;
  • 支付前系统本地相关业务处理 ;
  • 请求第三方支付服务执行扣款;
  • 第三方支付返回处理结果;
  • 本地服务基于支付结果响应客户端;

该业务流程中要处理相当复杂的问题,比如事务,分布式事务,接口延迟超时,客户端重复提交等等,这里只基于幂等接口角度来看该流程,其他问题后续再聊。

2、幂等接口

当上述流程的支付请求有明确结果的时候:失败或成功,这样业务流程都好处理,但是例如支付场景如果请求超时,如何判断服务的结果状态:客户端请求超时,本地服务超时,请求支付超时,支付回调超时,客户端响应超时等等。

这就需要设计流程化的状态管理。

3、基础操作案例

模拟管理上述流程,设计幂等接口:

表结构设计

CREATE TABLE `dp_order_state` (    `order_id` BIGINT (20) NOT NULL AUTO_INCREMENT COMMENT '订单id',    `token_id` VARCHAR (50) DEFAULT NULL COMMENT '防重复提交',    `state` INT (1) DEFAULT '1' COMMENT '1创建订单,2本地业务,3支付业务',    PRIMARY KEY (`order_id`)) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '订单状态表';CREATE TABLE `dp_state_record` (    `id` INT (11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',    `order_id` BIGINT (20) NOT NULL COMMENT '订单id',    `state_dec` VARCHAR (50) DEFAULT NULL COMMENT '状态描述',    PRIMARY KEY (`id`)) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '状态记录表';

模拟业务流程

将订单创建,本地业务,支付业务,分开分段管理提交。分阶段测试异常熔断的业务。

@Servicepublic class OrderServiceImpl implements OrderService {    @Resource    private OrderStateMapper orderStateMapper ;    @Resource    private StateRecordMapper stateRecordMapper ;    @Override    public OrderState queryOrder(OrderState orderState) {        Map<String,Object> paramMap = new HashMap<>() ;        paramMap.put("order_id",orderState.getOrderId());        List<OrderState> orderStateList = orderStateMapper.selectByMap(paramMap);        if (orderStateList != null && orderStateList.size()>0){            return orderStateList.get(0) ;        }        return null ;    }    @Override    public boolean createOrder(OrderState orderState) {        int saveRes = orderStateMapper.insert(orderState);        if (saveRes > 0){            saveStateRecord(orderState.getOrderId(),"订单创建成功");        }        return saveRes > 0 ;    }    @Override    public boolean localBiz(OrderState orderState) {        orderState.setState(2);        int updateRes = orderStateMapper.updateState(orderState) ;        if (updateRes > 0){            saveStateRecord(orderState.getOrderId(),"本地业务成功");        }        return updateRes > 0;    }    @Override    public boolean paymentBiz(OrderState orderState) {        orderState.setState(3);        int updateRes = orderStateMapper.updateState(orderState) ;        if (updateRes > 0){            saveStateRecord(orderState.getOrderId(),"支付业务成功");        }        return updateRes > 0;    }    private void saveStateRecord (Long orderId,String stateDec){        StateRecord stateRecord = new StateRecord() ;        stateRecord.setOrderId(orderId);        stateRecord.setStateDec(stateDec);        stateRecordMapper.insert(stateRecord) ;    }}

测试接口

根据订单状态,分段补偿执行未完成的业务,如果该订单已经完成,多次提交不影响最终结果。

@Api(value = "OrderController")@RestControllerpublic class OrderController {    @Resource    private OrderService orderService ;    @PostMapping("/submitOrder")    public String submitOrder (OrderState orderState){        OrderState orderState01 = orderService.queryOrder(orderState) ;        if (orderState01 == null){            // 正常业务流程            orderService.createOrder(orderState) ;            orderService.localBiz(orderState) ;            orderService.paymentBiz(orderState) ;        } else {            switch (orderState01.getState()){                case 1:                    // 订单创建成功:后推执行本地和支付业务                    orderService.localBiz(orderState01) ;                    orderService.paymentBiz(orderState01) ;                    break ;                case 2:                    // 订单本地业务成功:后推执行支付业务                    orderService.paymentBiz(orderState01) ;                    break ;                default:                    break ;            }        }        return "success" ;    }}

絮叨一句:实际开发中,该流程是不会由页面多次提交完成,订单是不能重复提交的,下面会演示如何控制,这里业务是执行后推到完成,也可能业务向前清理,把整个流程置为失败,这里涉及关键状态判断,要选取一个状态作为成功或失败的标识,判断后续操作流程。在分布式系统中这种复杂流程最难处理的是分布式事务,最终一致性问题,后续再聊。

三、接口重复提交

1、表单重复提交

在实际情况中,接口如果处理时间过长,用户可能会点击多次提交按钮,导致数据重复。

常见的一个解决方案:在表单提交中隐藏一个token_id参数,一起提交到接口服务中,数据库存储订单和关联的tokenId,如果多次提交,直接返回页面提示信息即可。

2、演示案例

订单关联Token查询

@Servicepublic class OrderServiceImpl implements OrderService {    @Override    public Boolean queryToken(OrderState orderState) {        Map<String,Object> paramMap = new HashMap<>() ;        paramMap.put("order_id",orderState.getOrderId());        paramMap.put("token_id",orderState.getTokenId());        List<OrderState> orderStateList = orderStateMapper.selectByMap(paramMap);        return orderStateList.size() > 0 ;    }}

测试接口

@RestControllerpublic class OrderController {    @Resource    private OrderService orderService ;    @PostMapping("/repeatSub")    public String repeatSub (OrderState orderState){        boolean flag = orderService.queryToken(orderState) ;        if (flag){            return "请勿重复提交订单" ;        }        return "success" ;    }}

四、源代码地址

GitHub·地址https://github.com/cicadasmile/data-manage-parentGitEE·地址https://gitee.com/cicadasmile/data-manage-parent

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

架构设计 | 接口幂等性原则,防重复提交Token管理

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

架构设计 | 接口幂等性原则,防重复提交Token管理

本文源码:GitHub·点这里 || GitEE·点这里一、幂等性概念1、幂等简介编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。就是说,一次和多次请求某一个资源会产生同样的作用影响。2、HTTP请求遵循Htt
2023-06-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录