通过注解实现接口限流防刷

采用注解的方式

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值超过最大访问次数时,拒绝用户访问。

原文地址:https://www.cnblogs.com/moris5013/p/12350059.html

时间: 2024-11-09 07:06:05

通过注解实现接口限流防刷的相关文章

SpringCloud(8)----zuul权限校验、接口限流

项目代码GitHub地址:https://github.com/yudiandemingzi/spring-cloud-study 一.权限校验搭建 正常项目开发时,权限校验可以考虑JWT和springSecurity结合进行权限校验,这个后期会总结,这里做个基于ZuulFilter过滤器进行一个简单的权限校验过滤. 对于组件zuul中,其实带有权限认证的功能,那就是ZuulFilter过滤器.ZuulFilter是Zuul中核心组件,通过继承该抽象类,覆写几个关键方法达到自定义调度请求的作用

Guava的RateLimiter实现接口限流

最近开发需求中有需要对后台接口进行限流处理,整理了一下基本使用方法. 首先添加guava依赖: <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.0</version> </dependency> 然后封装RateLimiter适用对多接口的限制: import com.goog

java接口限流算法

0. 前言 常见的限流算法有:令牌桶.漏桶.计数器也可以进行粗暴限流实现. 1. 算法介绍 1.1 令牌桶算法 令牌桶算法是一个存放固定容量令牌的桶,按照固定速率往桶里添加令牌.令牌桶算法的描述如下: 假设限制2r/s,则按照500毫秒的固定速率往桶中添加令牌: 桶中最多存放b个令牌,当桶满时,新添加的令牌被丢弃或拒绝: 当一个n个字节大小的数据包到达,将从桶中删除n个令牌,接着数据包被发送到网络上: 如果桶中的令牌不足n个,则不会删除令牌,且该数据包将被限流(要么丢弃,要么缓冲区等待). 1.

【Dnc.Api.Throttle】适用于.Net Core WebApi接口限流框架

Dnc.Api.Throttle    适用于Dot Net Core的WebApi接口限流框架 使用Dnc.Api.Throttle可以使您轻松实现WebApi接口的限流管理.Dnc.Api.Throttle支持IP.用户身份.Request Header.Request QueryString等多种限流策略,支持黑名单和白名单功能,支持全局拦截和单独Api拦截. Dnc.Api.Throttle暂时只支持Redis作为缓存和存储库,后续会进行扩展. 开始使用 安装Dnc.Api.Thrott

使用google的guova开发高并发下的接口限流

使用google的guova进行限流 1.guova的限流方式,在定时产生定量的令牌,令牌的数量限制了流量 2.增加一个订单接口限流类OrderRateFilter,继承ZuulFilter,并重载方法:filterType.filterOrder.shouldFilter.run ????filterType中return PRE_TYPE; ????fileterOrder中应该优先级最高,设为-4 ????shouldFilter中设置限流的方法(类似于鉴权) ???? RequestCo

接口限流实践

一.问题描述 某天A君突然发现自己的接口请求量突然涨到之前的10倍,没多久该接口几乎不可使用,并引发连锁反应导致整个系统崩溃.如何应对这种情况呢?生活给了我们答案:比如老式电闸都安装了保险丝,一旦有人使用超大功率的设备,保险丝就会烧断以保护各个电器不被强电流给烧坏.同理我们的接口也需要安装上“保险丝”,以防止非预期的请求对系统压力过大而引起的系统瘫痪,当流量过大时,可以采取拒绝或者引流等机制. 二.常用的限流算法 常用的限流算法有两种:漏桶算法和令牌桶算法,这篇博文介绍得比较清晰(过载保护算法浅

接口限流算法总结

背景 曾经在一个大神的博客里看到这样一句话:在开发高并发系统时,有三把利器用来保护系统:缓存.降级和限流.那么何为限流呢?顾名思义,限流就是限制流量,就像你宽带包了1个G的流量,用完了就没了.通过限流,我们可以很好地控制系统的qps,从而达到保护系统的目的.本篇文章将会介绍一下常用的限流算法以及他们各自的特点. 算法介绍 计数器法 计 数器法是限流算法里最简单也是最容易实现的一种算法.比如我们规定,对于A接口来说,我们1分钟的访问次数不能超过100个.那么我们可以这么做:在一开 始的时候,我们可

用nginx实现分布式限流(防DDOS攻击)

1.前言 一般对外暴露的系统,在促销或者黑客攻击时会涌来大量的请求,为了保护系统不被瞬间到来的高并发流量给打垮, 就需要限流 . 本文主要阐述如何用nginx 来实现限流. 听说 Hystrix 也可以, 各位有兴趣可以去研究哈 . 2. 首先部署一个对外暴露接口的程序 我这里部署的是一个spring boot 项目 里面暴露了如下接口, 很简单 package com.anuo.app.controller; import org.slf4j.Logger; import org.slf4j.

限流(二)接口限流

如果某个接口可能出现突发情况,比如"秒杀"活动,那么很有可能因为突然爆发的访问量造成系统奔溃,我们需要最这样的接口进行限流. 在上一篇"限流算法"中,我们简单提到了两种限流方式: 1)(令牌桶.漏桶算法)限速率,例如:每 5r/1s = 1r/200ms 即一个请求以200毫秒的速率来执行: 2)(计数器方式)限制总数.或者单位时间内的总数,例如:设定总并发数的阀值,单位时间总并发数的阀值. 一.限制总并发数 我们可以采用java提供的atomicLong类来实现