重复提交,你是如何处理的?

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 幂等性就是说无论你执行几次请求,其结果是一样的。说到了幂等就不得不说重复提交了,你连续点击提交按钮,理论上来说这是同一条数据,数据库应该只能存入一条,而实际上存放了多条,这就违反了幂等性。因此我们就需要做一些处理,来保证连续点击提交按钮后,数据库只能存入一条数据。

今天早上,新来的同事小王突然问我:“周哥,什么是幂等性啊?”。然后我就跟他解释了一番,幂等性就是说无论你执行几次请求,其结果是一样的。说到了幂等就不得不说重复提交了,你连续点击提交按钮,理论上来说这是同一条数据,数据库应该只能存入一条,而实际上存放了多条,这就违反了幂等性。因此我们就需要做一些处理,来保证连续点击提交按钮后,数据库只能存入一条数据。

防止重复提交的方式很多,这里我就说一下我认为比较好用的一种。

自定义注解+Aop实现

我们通过获取用户ip及访问的接口来判断他是否重复提交,假如这个ip在一段时间内容多次访问这个接口,我们则认为是重复提交,我们将重复提交的请求直接处理即可,不让访问目标接口。

自定义注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NoRepeatSubmit {

    /**
     * 默认1s钟以内算重复提交
     * @return
     */
    long timeout() default 1;
}

Aop处理逻辑

我们将ip+接口地址作为key,随机生成UUID作为value,存入redis。每次请求进来,根据key查询redis,如果存在则说明是重复提交,抛出异常,如果不存在,则是正常提交,将key存入redis。

@Aspect
@Component
public class NoRepeatSubmitAop {

    @Autowired
    private RedisService redisUtils;

    /**
     *     定义切入点
     */
    @Pointcut("@annotation(NoRepeatSubmit)")
    public void noRepeat() {}

    /**
     *     前置通知:在连接点之前执行的通知
     * @param point
     * @throws Throwable
     */
    @Before("noRepeat()")
    public void before(JoinPoint point) throws Exception{
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Assert.notNull(request, "request can not null");

        // 此处可以用token或者JSessionId
        String token = IpUtils.getIpAddr(request);
        String path = request.getServletPath();
        String key = getKey(token, path);
        String clientId = getClientId();
        List<Object> lGet = redisUtils.lGet(key, 0, -1);
        // 获取注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        NoRepeatSubmit annotation = method.getAnnotation(NoRepeatSubmit.class);
        long timeout = annotation.timeout();
        boolean isSuccess = false;
        if (lGet.size()==0 || lGet == null) {
            isSuccess = redisUtils.lSet(key, clientId, timeout);
        }
        if (!isSuccess) {
            // 获取锁失败,认为是重复提交的请求
            redisUtils.lSet(key, clientId, timeout);
            throw new Exception("不可以重复提交");
        }

    }

    private String getKey(String token, String path) {
        return token + path;
    }

    private String getClientId() {
        return UUID.randomUUID().toString();
    }
}

提供接口用来测试

在接口上添加上我们自定义的注解@NoRepeatSubmit

@RequestMapping("/test")
@NoRepeatSubmit
public String tt(HttpServletRequest request) {

    return "1";
}

测试

我们在浏览器中连续请求两次接口。发现第一次接口响应正常内容:1,第二次接口响应了不可重复提交的异常信息。1s之后再点击接口,发现又响应了正常内容。

至此,这种防止重复提交的方式就介绍完了,这样我们就完美防止了接口重复提交。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
目录
相关文章
|
存储 缓存 JavaScript
缓存组件状态,提升用户体验:探索 keep-alive 的神奇世界
缓存组件状态,提升用户体验:探索 keep-alive 的神奇世界
缓存组件状态,提升用户体验:探索 keep-alive 的神奇世界
|
12月前
|
数据采集 存储 数据处理
通过load->model()加载数据模型:在采集中实现动态数据处理
本文介绍了在现代网络爬虫技术中,动态数据处理的重要性和实现方法。文章以采集小红书短视频为例,详细讲解了如何通过`load->model()`方法加载数据模型来处理动态数据。首先,强调了动态数据处理在爬虫技术中的必要性,尤其是对于需要实时更新或用户交互的网页。接着,通过安装必要的Python库,使用代理IP技术,设置User-Agent和Cookie,以及动态加载数据模型的步骤,展示了如何构建一个高效的爬虫系统。文章还提供了完整的代码示例,包括环境准备、代理IP配置、请求头设置、数据模型加载和数据解析等关键步骤,成功应用于小红书短视频数据的采集。
283 13
通过load->model()加载数据模型:在采集中实现动态数据处理
|
9月前
|
安全 小程序
|
11月前
|
数据可视化 数据挖掘 大数据
Python 数据分析入门:从零开始处理数据集
Python 数据分析入门:从零开始处理数据集
|
存储 算法 Java
(五)漫谈分布式之一致性算法篇:谁说Paxos晦涩难懂?你瞧这不一学就会!
没在时代发展的洪流中泯然于众的道理很简单,是因为它们并不仅是空中楼阁般的高大上理论,而是有着完整落地的思想,它们已然成为构建分布式系统不可或缺的底层基石,而本文则来好好聊聊分布式与一致性思想的落地者:Paxos与Raft协议(算法)。
237 6
技术笔记:PID控制器开发笔记之十一:专家PID控制器的实现
技术笔记:PID控制器开发笔记之十一:专家PID控制器的实现
|
前端开发 JavaScript 测试技术
"React新手入门的神奇之处:如何用React构建第一个应用,让你的项目一鸣惊人?"
【8月更文挑战第31天】本文详细介绍了如何从头开始构建首个React应用。React作为当今Web开发中备受欢迎的前端框架,采用组件化设计实现界面构建,便于维护与扩展。文章首先解释了React的基础概念,接着演示了使用Create React App搭建项目的步骤,展示了基础组件编写方法及React Router的简单运用,并分享了一些实用的最佳实践建议,帮助读者快速上手React开发。
194 0
|
JavaScript 测试技术 API
顺藤摸瓜🍉:用单元测试读懂 vue3 中的 defineComponent
顺藤摸瓜🍉:用单元测试读懂 vue3 中的 defineComponent
|
缓存 JavaScript 网络协议
访问git和vue很慢如何解决
解决Git和Vue官网访问慢的问题,通过修改Windows的HOSTS文件。添加GitHub和Vue特定IP地址,例如github.com、cn.vuejs.org等,然后执行`ipconfig/flushdns`刷新DNS缓存,以提高访问速度。记得先备份HOSTS文件。
164 1