springboot 接口频率限制

1.使用场景

      针对耗时操作的接口,避免在短时间内重复请求,在后端用拦截器对请求进行拦截过滤,判断请求频率是否在合理时间范围内。

2.实现方式

 

@Component
public class RequestFrequenceInterceptor implements HandlerInterceptor {
    private static Logger log = LoggerFactory.getLogger( RequestFrequenceInterceptor.class );

    private long lastTime = 0;
    private boolean startDelay(int time) {
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastTime > time) {
            System.out.println(currentTime + " - " + lastTime);
            lastTime = currentTime;
            return true;
        }

        return false;
    }
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String ip = CommontMethod.getIpAddr( request );//获取ip地址
        //开始进入请求地址拦截
        //获取执行方法上的注解  不过滤静态资源
        if(handler instanceof  HandlerMethod){
            HandlerMethod hm = (HandlerMethod) handler;
            //对包含注解的方法进行频率验证
            Delay delay = hm.getMethodAnnotation(Delay.class);
            if (delay != null) {
                if ( startDelay(delay.time()))
                {
                    return true;
                }else {
                    log.warn( ip+" 请求频率过快" );
                    Map<String,Object> responseMap = new HashMap<>(  );
                    responseMap.put( "code", SystemCode.LOCK_USER.getCode() );
                    responseMap.put( "message","请求被锁定,频率过快" );
                    String resStr = JsonUtil.toJsonStr(responseMap);
                    response.setContentType("application/json;charset=utf-8");
                    response.setHeader("Access-Control-Allow-Origin", "*");
                    response.setHeader("Cache-Control","no-cache");
                    response.getWriter().write(resStr);

                    return false;
                }
            }
        }



        //  对于不包含注解的方法一律放行
        return true;

    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        //处理请求完成后紧接着的操作
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
       //视图渲染之后的操作
    }
}

 2.自定义时间注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Delay {
//默认两秒,意思是每个方法两秒内只能请求一次,重复请求无效
    int time() default 2000;

}

3.注册拦截器

@Configuration
public class RequestParamInterceptorConf implements WebMvcConfigurer {
    @Autowired
    RequestParamInterceptor requestParamInterceptor;
    @Autowired
    RequestFrequenceInterceptor frequenceInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        // 多个拦截器组成一个拦截器链
        // addPathPatterns 用于添加拦截规则
        // excludePathPatterns 用户排除拦截
        // TokenInterceptor()为自己定义的拦截器
        registry.addInterceptor(requestParamInterceptor).addPathPatterns("/**").excludePathPatterns("/error");
        registry.addInterceptor( frequenceInterceptor ).addPathPatterns( "/**" ).excludePathPatterns("/error");
    }
}

4.获取请求ip小工具

public class CommontMethod {

	/**
     * 获取请求ip
	 * @param request 
	 * @return 
	 */  
	public static String getIpAddr(HttpServletRequest request){
	    String ipAddress = request.getHeader("x-forwarded-for");  
	        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
	            ipAddress = request.getHeader("Proxy-Client-IP");  
	        }  
	        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
	            ipAddress = request.getHeader("WL-Proxy-Client-IP");  
	        }  
	        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
	            ipAddress = request.getRemoteAddr();  
	            if("127.0.0.1".equals(ipAddress) || "0:0:0:0:0:0:0:1".equals(ipAddress)){  
	            	 //根据网卡取本机配置的IP  
	                InetAddress inet=null;
	                try {  
	                    inet = InetAddress.getLocalHost();  
	                } catch (UnknownHostException e) {
	                    e.printStackTrace();  
	                }  
	                ipAddress= inet.getHostAddress();  
	            }  
	        }  
	        //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割  
	        if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15  
	            if(ipAddress.indexOf(",")>0){  
	                ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));  
	            }  
	        }  
	        return ipAddress;   
	}

}

 

总结:要使用该注解,直接在要使用的方法上@Dely(value=5000)即可

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我先森

鼓励一个吧,哈哈

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值