zoukankan      html  css  js  c++  java
  • 通过注解实现接口限流防刷

    采用注解的方式

    1)定义一个注解

    @Retention(RUNTIME)
    @Target(METHOD)
    public @interface AccessLimit {
        int seconds();
        int maxCount();
    }

    2)在需要限流的方法前加这样的注解

    @AccessLimit(seconds=5, maxCount=5)

    3)在拦截器里进行判断,看方法是否使用了AccessLimit注解修饰

    @Component
    public class AccessInterceptor  extends HandlerInterceptorAdapter{
        
        @Autowired
        MiaoshaUserService miaoshaUserService;
        
        @Autowired
        RedisService redisService;
        
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            System.out.println("prehandle....");
            if(handler instanceof HandlerMethod) {
                HandlerMethod hm = (HandlerMethod)handler;
                String methodName = hm.getMethod().getName();
                if(methodName.equals("toLogin") || methodName.equals("do_login")){
                    return true;
                }else{
                    //获取用户登录信息放入线程上下文中
                    MiaoshaUser user = getUser(request, response);
                    UserContext.setUser(user);
    
                    //判断防刷限流注解
                    AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
                    if(accessLimit == null) {
                        return true;
                    }
                    int seconds = accessLimit.seconds();
                    int maxCount = accessLimit.maxCount();
                    String key = request.getRequestURI();
                    AccessKey ak = AccessKey.withExpire(seconds);
                    Integer count = redisService.get(ak, key, Integer.class);
                    if(count  == null) {
                        redisService.set(ak, key, 1);
                    }else if(count < maxCount) {
                        redisService.incr(ak, key);
                    }else {
                        render(response, CodeMsg.ACCESS_LIMIT_REACHED);
                        return false;
                    }
                }
            }
            return true;
        }
        
        private void render(HttpServletResponse response, CodeMsg cm)throws Exception {
            response.setContentType("application/json;charset=UTF-8");
            OutputStream out = response.getOutputStream();
            String str  = JSON.toJSONString(Result.error(cm));
            out.write(str.getBytes("UTF-8"));
            out.flush();
            out.close();
        }
    
        private MiaoshaUser getUser(HttpServletRequest request, HttpServletResponse response) {
            String paramToken = request.getParameter(MiaoshaUserService.COOKI_NAME_TOKEN);
            String cookieToken = getCookieValue(request, MiaoshaUserService.COOKI_NAME_TOKEN);
            if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
                throw new GlobalException(CodeMsg.SESSION_ERROR);
            }
            String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
         //这里是从redis中取用户信息 MiaoshaUser miaoshaUser
    = miaoshaUserService.getByToken(response, token); if(null == miaoshaUser){ throw new GlobalException(CodeMsg.SESSION_ERROR); } return miaoshaUser; } private String getCookieValue(HttpServletRequest request, String cookiName) { Cookie[] cookies = request.getCookies(); if(cookies == null || cookies.length <= 0){ return null; } for(Cookie cookie : cookies) { if(cookie.getName().equals(cookiName)) { return cookie.getValue(); } } return null; } }
    public class UserContext {
        
        private static ThreadLocal<MiaoshaUser> userHolder = new ThreadLocal<MiaoshaUser>();
        
        public static void setUser(MiaoshaUser user) {
            userHolder.set(user);
        }
        
        public static MiaoshaUser getUser() {
            return userHolder.get();
        }
    
    }

    思路是:用户第一次请求过来后,将url和用户id拼接作为key,1作为value值设置到redis中,并设置过期时间。用户下次请求过来,采用redis的自增,当value值超过最大访问次数时,拒绝用户访问。

  • 相关阅读:
    如何远程关闭一个ASP.NET Core应用?
    Asp.Net Core 2.x 和 3.x WebAPI 使用 Swagger 时 API Controller 控制器 Action 方法 隐藏 hidden 与 and 分组 group
    Swashbuckle.AspNetCore3.0的二次封装与使用
    微服务日志之.NET Core使用NLog通过Kafka实现日志收集
    细说ASP.NET Core静态文件的缓存方式
    ASP.NET Core中的ActionFilter与DI
    查看.NET Core源代码通过Autofac实现依赖注入到Controller属性
    使用 python set 去重 速度到底是多快呢???
    搜狐视频 登录 md5 加密破解
    python 实现 DES CBC模式加解密
  • 原文地址:https://www.cnblogs.com/moris5013/p/12350059.html
Copyright © 2011-2022 走看看