内容简介:今天早上,新来的同事小王突然问我:“周哥,什么是幂等性啊?”。然后我就跟他解释了一番,幂等性就是说无论你执行几次请求,其结果是一样的。说到了幂等就不得不说重复提交了,你连续点击提交按钮,理论上来说这是同一条数据,数据库应该只能存入一条,而实际上存放了多条,这就违反了幂等性。因此我们就需要做一些处理,来保证连续点击提交按钮后,数据库只能存入一条数据。防止重复提交的方式很多,这里我就说一下我认为比较好用的一种。我们通过获取用户ip及访问的接口来判断他是否重复提交,假如这个ip在一段时间内容多次访问这个接口,我们
今天早上,新来的同事小王突然问我:“周哥,什么是幂等性啊?”。然后我就跟他解释了一番,幂等性就是说无论你执行几次请求,其结果是一样的。说到了幂等就不得不说重复提交了,你连续点击提交按钮,理论上来说这是同一条数据,数据库应该只能存入一条,而实际上存放了多条,这就违反了幂等性。因此我们就需要做一些处理,来保证连续点击提交按钮后,数据库只能存入一条数据。
防止重复提交的方式很多,这里我就说一下我认为比较好用的一种。
自定义注解+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之后再点击接口,发现又响应了正常内容。
至此,这种防止重复提交的方式就介绍完了,这样我们就完美防止了接口重复提交。
以上所述就是小编给大家介绍的《重复提交,你是如何处理的?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Git提交错误时如何删除Git提交记录
- 分布式系统 - 两段式提交(2PC)和三段式提交(3PC)
- 减半前,比特币开发者代码提交数创历史新高:4月累计提交510次
- 提交任务到Spark
- [译] Commit 提交指南
- Git合并提交
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。