首页 > 其他分享 >避免重复提交(幂等性处理)

避免重复提交(幂等性处理)

时间:2024-08-09 09:38:46浏览次数:15  
标签:responseText 重复 idempotent 点击 idempotentToken 避免 提交 按钮

什么是重复提交

提交:你打开个网页,要注册个邮箱,你点击注册按钮后成功了,就是一次成功的数据提交。
重复提交:相当于在点击了一次注册按钮,但是因为网络波动,页面没有响应,此时你又点击了一次注册按钮(多次点击)。网络波动恢复,但是此时给后台传输的数据是两条一样的数据。如果不进行处理,将会以同样的用户数据注册了两个账号。

危害性:就像你买东西给某人转账,确定转 200元,但是因为手机网络信号不好,支付按钮点了一次没用。你有点疑惑,继续点了点,还是没反应。逐渐暴躁,点了多次按钮。突然,网络恢复正常,你发现本来只想转一次 200,变成转了 200次 200。同时那个人收款后直接把你拉黑了。。。。。。真实的令人发指

防止重复提交,就是实现幂等性:在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同
一个转账场景下,点击了一次转账跟点击了多次转账按钮效果一样,只转一次

如何防止重复提交

  • 前端控制
    • 控制按钮:按钮点击一次后,再未接受到后台返回值之前,不可再点击
    • 页面跳转:点击按钮后,直接跳转到一个静态页面。(也是控制按钮的不可再点击)
    • 提交数据识别:对于按钮提交的参数进行识别,看是否是相同的参数
  • 后台控制

前端控制实现

/**
* 全局属性,用于保存提交参数的 hashCode。起到缓存的作用
*/
watcher: {},
    
/**
* ajax 统一调用接口
* jsonData:传递给后台的的参数
*/
JsonRequest(jsonData) {
    let me = this, e = $Defer(), w = this.watcher
    // 对于参数进行 hashCode 生成唯一标识码保存在全局属性中。
    const uniqueId = this.hashcode(jsonData)
    // add by YangL 前端防重提交控制
    if (w[uniqueId]) {
        e.reject({msg: "服务器正在处理您的请求,请稍后...^_^"});
        return e.promise;
    }
    w[uniqueId] = true;
    // 进行 ajax 异步处理(自定义方法)
    me.RequestAsync(jsonData).then(function (n) {
        // 后台返回数据
        w[uniqueId] = false
        e.resolve(n)
    }, function (n) {
        // 后台fan'hui'shu'j
        w[uniqueId] = false
        e.reject(n)
    })
    return e.promise;
},

后台控制实现

通过token

服务器端判断客户端提交上来的 Token 与服务器端生成的 Token 是否一致,如果不一致,那就是重复提交了。

public class IdempotentAspect implements MethodInterceptor, ThrowsAdvice {
    private static final Logger log = LoggerFactory.getLogger(IdempotentAspect.class);
    private static final String SIGN_RUNNING = "running";
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        Idempotent idempotent = (Idempotent)methodInvocation.getMethod().getAnnotation(Idempotent.class);
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        String idempotentToken = request.getHeader("idempotent_token");
        if (S.isEmpty(idempotentToken)) {
            throw new AccessDeniedException("请求被拒绝,请求头参数[idempotent_token]不能为空!");
        } else {
            idempotentToken = "rbmh_idemp:token:" + idempotentToken;
            if (!RedisUtils.hasKey(idempotentToken)) {
                throw new AccessDeniedException("请求被拒绝,请求头参数[idempotent_token]不存在或已过期!");
            } else {
                String responseText = (String)RedisUtils.get(idempotentToken);
                if (responseText == null) {
                    responseText = (String)RedisUtils.getAndSet(idempotentToken, "running");
                    if (responseText != null) {
                        return this.reject(idempotentToken, responseText, idempotent);
                    } else {
                        Object response = methodInvocation.proceed();
                        this.resolve(idempotentToken, response);
                        return response;
                    }
                } else {
                    return this.reject(idempotentToken, responseText, idempotent);
                }
            }
        }
    }
}

标签:responseText,重复,idempotent,点击,idempotentToken,避免,提交,按钮
From: https://www.cnblogs.com/Kevin-QAQ/p/18350189

相关文章

  • 【mysql随机获取3条不重复数据】最佳实践
    需求:从商品库中随机获取3个不重复的商品,推荐给用户。假设product表数据为10000行。方案一【最佳实际】1.mysql数据库中获取所有商品数据的IDselectidfromproduct;2.通过Java获取随机3个商品ID//假设List中存的为上述数据库ID值List<Integer>productIdList=newA......
  • leetcode 718. 最长重复子数组,leetcode 1143. 最长公共子序列
    leetcode718和leetcode1143两道十分相似的题,就不放题目了思路实际上区别就在于一个要求连续数组,另一个要求不连续的序列。二者的dp表达式和状态转移其实是不一致的,前者f[i][j]代表nums1以i结尾nums2以j结尾的最长子数组长度,后者代表nums1以i结尾nums2以j结尾的区间内存......
  • Git合并之————指定提交记录合并
    应用场景在测试环境提交了多个功能代码,其中一个功能需要提前上线如图所示,红框部分为我本次需要上线的功能提交记录代码,绿框部分为我已选择上线成功,可以看到红框与绿框直接的内容并没有被带入master分支.这里我以IDEA为例.首先,切换到master分支,也就是你需要......
  • OKR和绩效考核:应避免的四个陷阱
    OKRs是一个组织的绩效管理工具箱的重要组成部分。很容易想让它们与其他工具紧密互动,即绩效考核也就是评估。从那里,将它们结合在一个软件解决方案中,这太诱人了。但我非常熟悉这带来的负面后果,强调将员工评价和OKR归为一类的关键问题,并概述我所看到的行之有效的方法。在我们开始之......
  • 第五节:QPS突然提升100倍、不用redis锁防止重复点击、如何设计订单号生成服务
    一.        二.        三.         !作       者:Yaopengfei(姚鹏飞)博客地址:http://www.cnblogs.com/yaopengfei/声     明1:如有错误,欢迎讨论,请勿谩骂^_^。声     明2:原创博客请在转载......
  • MySQL删除重复记录并且只保留最新一条
    目录测试表方式一:分组查询出每组最大的ID,其余的删除方式二:先标记重复待清理的数据,检查后清理附言查询所有重复的列:这里给到MySQL5.7和8.0版本的查询方式在开发过程中,因为某些问题可能会导致同一条数据在表中重复出现,此时我们需要申请权限走SQL去修复,下面介绍下具体修......
  • 【practise】删除有序数组中的重复项
    关于博主:今天分享一道简单的关于“双指针”算法的题目。算是双指针中非常基础的题目,有兴趣可以借鉴一波~目录1.题目介绍2.题解思路:`双指针法`3.代码示例1.题目介绍题目链接:LINK本题要求是:对给定的有序数组nums删除重复元素,使得每种元素仅在该数组中出现一次,......
  • NC 没有重复项数字的全排列
    系列文章目录文章目录系列文章目录前言前言前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。描述给出一组数字,返回该组数字的所有排列例如:[1,2,3]的所有排列如下[......
  • Element el-form 表单校验,保存或提交验证某一项或者多项;validateField 的使用
    通常新增或者编辑对form表单的校验都是全局性的校验:this.$refs.form.validate(valid=>{if(valid){//校验通过,业务逻辑代码...}});如果需要对表单里的特定几个必填项进行校验,应该如何实现? 业务场景:下图点击保存按钮时,只需要校验前两项,其余参数不......
  • Redis可以通过以下几种方式来避免内存溢出
    Redis可以通过以下几种方式来避免内存溢出:设置最大内存限制:可以使用maxmemory配置项来限制Redis的最大内存使用量。当Redis的内存占用超过了设置的最大内存限制时,Redis会根据所配置的内存策略来处理数据,例如删除最近最少使用的键或者拒绝写入请求。使用内存淘汰策略:当......