接口访问次数限制


接口访问次数限制(request_limit)
================================================================================
利用spring切面或拦截器实现;

可以对所有接口或添加注解的接口实现请求次数限制;

利用缓存的过期时间功能,uri太长可以做个映射(为缓存节省空间);

ip要防止利用代理访问;

限制维度:ip级别、用户+接口级别;

*******************************注解类
/**
 * request请求次数限制
 * 示例:@RequestLimit(ipCount=2,ipTime=60000,uriCount=2,uriTime=60000)
 * @date 2016-03-23 13:28:06
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface RequestLimit {

    /**
     * ip允许访问的次数,默认值1000
     */
    int ipCount() default 1000;

    /**
     * ip时间段,单位为毫秒,默认值一分钟
     */
    long ipTime() default 60000;
    
    /**
     * uri允许访问的次数,默认值600
     */
    int uriCount() default 600;

    /**
     * uri时间段,单位为毫秒,默认值一分钟
     */
    long uriTime() default 60000;

}
*******************************

*******************************spring切面
public Object around(ProceedingJoinPoint pjp)  {
//拦截的实体类
    Object target = pjp.getTarget();
    //拦截的方法名称
    String methodName = pjp.getSignature().getName();
    //拦截的放参数类型
    Class[] parameterTypes = ((MethodSignature)pjp.getSignature()).getMethod().getParameterTypes();
    Class[] clazzs = target.getClass().getInterfaces();
    //1.获取类
    Class clazz = target.getClass();
    if (clazzs != null && clazzs.length > 0){
        clazz = clazzs[0];
    }
    //2.获取方法
    Method m = clazz.getMethod(methodName, parameterTypes);
    //3.获取request、callback
    Object[] args = pjp.getArgs();
    HttpServletRequest request = null;
    if (args != null && args.length > 0) {
        if (args[0] instanceof HttpServletRequest) {
            request = (HttpServletRequest) args[0];
            if(request != null){
                callback = request.getParameter("callback");
            }
        }
    }
    //RequestLimit判断
    String reequestLimitRes = this.RequestLimitCheck(m, request);
    if("fail".equals(reequestLimitRes)){
        return "fail";//返回值改为自己的格式
    }else{
        Object obj = pjp.proceed();
    }
}

private String RequestLimitCheck(Method m, HttpServletRequest request) throws IOException{
    //ip、user_phone+uri  两个维度的访问限制
    if(m!=null && m.isAnnotationPresent(RequestLimit.class)){
        RequestLimit requestLimit = m.getAnnotation(RequestLimit.class);
        //失效时间、访问次数
        int ipTime = (int) (requestLimit.ipTime() / 1000);
        int ipCount = requestLimit.ipCount();
        int uriTime = (int) (requestLimit.uriTime() / 1000);
        int uriCount = requestLimit.uriCount();

        //ip、user_phone、uri
        String ip_key = NetworkUtil.getIpAddress(request);//ip:获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址;
        String user_phone = request.getParameter("user_phone");//手机号
        String uri = request.getRequestURI().toString();//uri:如果字符串太长,可以做个映射
        String user_uri_key = user_phone + uri;
        //先从缓存中(以Memcached为例)获取两个key对应的value值,value值为访问限制次数
        List<String> keyCollections = new ArrayList<String>();
        keyCollections.add(ip_key);
            keyCollections.add(user_uri_key);
        Map<String, String> valueMap = memcachedClient.get(keyCollections);//一次读取出多个key_value
        Integer ipNumCache = 0;//ip访问次数
            Integer userUriNumCache = 0;//手机号+uri访问次数
            if(valueMap!=null && valueMap.size()>0){
                String ipNumCacheFlag = valueMap.get(ip_key);
                if(StringUtils.isNotBlank(ipNumCacheFlag)){
                    ipNumCache = Integer.parseInt(ipNumCacheFlag);
                }
                String userUriNumCacheFlag = valueMap.get(user_uri_key);
                if(StringUtils.isNotBlank(userUriNumCacheFlag)){
                    userUriNumCache = Integer.parseInt(userUriNumCacheFlag);
                }
            }
        //ip限制判断
            if(ipNumCache == 0){
                memcachedClient.set(ip_key, 1, ipTime);
            }else if(ipNumCache >= ipCount){
                logger.info("request_limit:用户IP[" + ip_key + "],超过了限定的次数[" + ipCount + "]");
                return "fail";
            }else{
                memcachedClient.incr(ip_key, 1);//自增
            }
        //user_phone、uri限制判断
        if(userUriNumCache == 0){
            memcachedClient.set(user_uri_key, 1, uriTime);
        }else if(userUriNumCache >= uriCount){
            logger.info("request_limit:用户手机号[" + user_phone + "],访问地址[" + uri + "],超过了限定的次数[" + uriCount + "]");
            return "fail";
        }else{
            memcachedClient.incr(user_uri_key, 1);
        }
    }
    return "success";
}
*******************************
后续:

可以将不正常调用的用户添加进黑名单,保存在数据库中...

爬虫项目会定期定时访问接口,后台分析...



  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值