接口幂等性的解决

1.前端防重

通过前端防重保证幂等是最简单的实现方式,前端相关属性和JS代码即可完成设置。可靠性并不好,有经验的人员可以通过工具跳过页面仍能重复提交。主要适用于表单重复提交或按钮重复点击

2.PRG模式

PRG模式即POST-REDIRECT-GET。当用户进行表单提交时,会重定向到另外一个提交成功页面,而不是停留在原先的表单页面。这样就避免了用户刷新导致重复提交。同时防止了通过浏览器按钮前进/后退导致表单重复提交。是一种比较常见的前端防重策略

3.唯一标识(token机制)

1.方案介绍:通过唯一标识机制来保证幂等是一种非常常见的解决方案,同时也适合绝大部分场景。该方案需要前后端进行一定程度的交互来完成

请添加图片描述
2.流程如下:

  1. 服务端提供获取token接口,供客户端进行使用。服务端生成token后,如果当前为分布式架构,将token存放于redis中,如果是单体架构,可以保存在jvm缓存中
  2. 当客户端获取到token后,会携带着token发起请求
  3. 服务端接收到客户端请求后,首先会判断该token在redis中是否存在。如果存在,则删除token,再完成进行业务处理,业务处理完成后。如果不存在,代表当前请求是重复请求,直接向客户端返回对应标识

4.唯一标识(token机制)的实现

1.基于自定义业务流程实现(代码忽略)
在这里插入图片描述
2.基于注解方式

直接把token实现嵌入到方法中会造成大量重复代码的出现。因此可以通过自定义注解将上述代码进行改造。在需要保证幂等的方法上,添加自定义注解即可

3.定义一个注解

/**
* 幂等性注解
*/
@Target({
    
    ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Idemptent {
    
    
}

4.新建拦截器

public class IdempotentInterceptor implements HandlerInterceptor {
    
    

    @Resource
    private RedisTemplate redisTemplate;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        if (!(handler instanceof HandlerMethod)){
    
    
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        Idempotent annotation = method.getAnnotation(Idempotent.class);
        if (annotation != null){
    
    
            //幂等性校验
            checkToken(request);
        }
        return true;
    }

    private void checkToken(HttpServletRequest request) {
    
    

        //获取token
        String token = request.getHeader("token");

        if (StringUtils.isEmpty(token)){
    
    
            throw new RuntimeException("非法参数");
        }

        Boolean deleteResult = redisTemplate.delete(token);
        if (!deleteResult){
    
    
            //重复请求
            throw new RuntimeException("重复请求");
        }
    }
}

5.启动类继承WebMvcConfigurerAdapter并且添加如下代码:

 @Bean
 public IdempotentInterceptor idempotentInterceptor(){
    
    
     return new IdempotentInterceptor();
 }

 @Override
 public void addInterceptors(InterceptorRegistry registry) {
    
    
     registry.addInterceptor(idempotentInterceptor());
     super.addInterceptors(registry);
 }

猜你喜欢

转载自blog.csdn.net/weixin_44702984/article/details/131603200