当前位置:   article > 正文

结合Redis基于Token机制处理接口幂等性问题_redis token

redis token

在处理接口幂等性之前我们先说说什么是接口幂等性

幂等性就是对于同一个接口,如果使用相同的参数,执行多次,得到的结果却是一样的,一般主要处理的是添加、删除、更新这三种类型的接口,查询接口是不需要的,查询并不会影响数据库中的数据。

在发送多个参数相同的同一请求时,为了确保只返回一次结果的效果,这就是幂等性

解决幂等性的办法有很多种,如Token机制、利用MySQL的唯一索引机制来建立去重表、为要处理的结果设置状态字段、使用Redis的setnx、锁机制等等。

接下来小编将基于Token机制来对接口幂等性问题进行处理。

Token机制

首先客户端请求服务端,获取一个token,每一次请求都获取一个全新的token,将token存入到redis中,然后将token返回给客户端。

客户端将携带刚刚返回的token去请求一个接口,此时服务端收到请求后将对token进行判断,

a.如果token存在redis中,直接删除token,然后继续处理业务请求。

b.如果token不存在redis中,说明token已过期或者当前业务已经执行过了,那么就不在往下处理业务逻辑。

小编将使用拦截器基于token机制来对幂等性进行处理,SpringBoot以及Redis的配置就不进行演示了,直接上干货!

1.自定义注解

首先,我们需要自定义一个注解,将注解添加到需要进行幂等性处理的接口上即可,将来这个接口将会自动进行幂等性处理

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.METHOD)
  3. public @interface Idemponent {
  4. }

2.定义Redis

定义RedisService类,判断redis中是否存在token令牌,以及保存token令牌和删除token令牌,

在保存token令牌时设定令牌有效时间为5分钟,删除token时判断当前令牌是否还存在redis中,是否已被删除。

  1. public class RedisService {
  2. @Autowired
  3. StringRedisTemplate redisTemplate;
  4. public boolean hasToken(String token) {
  5. return redisTemplate.hasKey(token);
  6. }
  7. public boolean deleteToken(String token) {
  8. //删除前判断token是否被删除
  9. if(hasToken(token)){
  10. return redisTemplate.delete(token);
  11. }
  12. return false;
  13. }
  14. public void saveToken(String s) {
  15. redisTemplate.opsForValue().set(s,s);
  16. redisTemplate.expire(s, Duration.ofMinutes(5));
  17. }
  18. }

3.定义Token令牌

小编定义了一个TokenService来对token令牌的验证以及获取,定义了令牌校验方法checkToken()和令牌获取方法getToken(),令牌内容是由UUID随机生成的。在checkToken()中,如果令牌存在redis中,则删除该令牌。

  1. public class TokenService {
  2. @Autowired
  3. RedisService redisService;
  4. public boolean checkToken(HttpServletRequest request, HttpServletResponse response)
  5. {
  6. String token = request.getHeader("token");
  7. if (token == null || "".equals(token)) {
  8. //如果请求头为空则从参数中获取
  9. token = request.getParameter("token");
  10. if (token == null || "".equals(token)) {
  11. //说明没有传递令牌
  12. throw new IdemponentException("令牌不存在,请求失败");
  13. }
  14. }
  15. //判断令牌是否存在redis 中
  16. boolean result = redisService.hasToken(token);
  17. if (result) {
  18. //存在令牌
  19. return redisService.deleteToken(token);
  20. }
  21. //如果redis中不存在该令牌
  22. return false;
  23. }
  24. public String getToken() {
  25. String s = UUID.randomUUID().toString();
  26. redisService.saveToken(s);
  27. return s;
  28. }
  29. }

4.解析自定义注解

通过拦截器来对自定义的注解进行解析,实现HandlerInterceptor接口,重写preHandle方法即可。

  1. public class IdemponentInterceptor implements HandlerInterceptor {
  2. @Autowired
  3. TokenService tokenService;
  4. @Override
  5. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  6. if(handler instanceof HandlerMethod){
  7. //说明拦截下来的是接口方法
  8. HandlerMethod handlerMethod = (HandlerMethod) handler;
  9. // 获取接口方法上的注解
  10. Idemponent methodAnnotation = handlerMethod.getMethodAnnotation(Idemponent.class);
  11. if (methodAnnotation != null) {
  12. //如果注解不为空,说明接口方法存在
  13. //检验令牌
  14. boolean b = tokenService.checkToken(request, response);
  15. if (!b){
  16. response.setContentType("text/html;charset=utf-8");
  17. response.getWriter().write("请求重复");
  18. }
  19. return b;
  20. }
  21. }
  22. //说明这个接口不存在,则放行
  23. return true;
  24. }
  25. }

5.配置拦截器

做完以上步骤后,最后配置一下拦截器,拦截所有请求。

  1. public class WebConfig implements WebMvcConfigurer {
  2. @Autowired
  3. IdemponentInterceptor interceptor;
  4. @Override
  5. public void addInterceptors(InterceptorRegistry registry) {
  6. //拦截所有请求
  7. registry.addInterceptor(interceptor).addPathPatterns("/**");
  8. }
  9. }

这样我们的接口幂等性问题就解决了,只需要将自定义注解加在需要处理幂等性的接口上就好啦

最后总结一下我们都做了哪些事:

1.自定义注解,将注解加在需要幂等性处理的接口上方便进行处理。

2.定义RedisService类,调用方法haskey()判断redis中是否存在token令牌,保存token令牌,调用expire()为token设置有效时长,删除token前判断token是否已被删除。

3.定义Token令牌,从请求头或请求参数中获取token信息,如果没有获取token令牌,则抛出异常,说明token没有发送过来,接着判断token是否存在,如果不存在则不再往下进行逻辑处理如果存在则删除,下一次请求访问时就不用继续往下进行逻辑处理。

4.通过拦截器解析自定义注解,拦截器会拦截请求,我们只需获取添加了自定义注解的接口即可,获取接口之后校验token令牌,如果存在则放行,不存在则说明多次发送参数相同的同一请求(注意:第一次发送请求时会从redis中删除token并放行,之后再次请求redis中将不存在该token)

5.配置拦截器,拦截所有请求。

注意:在发送请求前需要先获取token令牌,获取token令牌接口如下:

  1. @GetMapping("/token")
  2. public String getToken(){
  3. return tokenService.getToken();
  4. }

以上就是使用Token机制处理接口幂等性问题的方法讲解啦,希望能够帮助到小伙伴们!点点赞哦~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/425880
推荐阅读
相关标签
  

闽ICP备14008679号