0
点赞
收藏
分享

微信扫一扫

根据登陆ip,限制1分钟最多10次服务请求,须支持单机并发场景,请使用java代码原生实现

鱼板番茄 2022-04-14 阅读 22

       由于业务系统服务接口被竞对高频爬取,我们需要上线一个防刷限流功能。场景要求如下:根据登陆ip,限制1分钟最多10次服务请求,须支持单机并发场景,请使用java代码原生实现(勿使用中间件redis、计数器之类方案)。

// 请完善如下模板代码

public class Solution {
        //不限流返回ture,限流返回false
        public boolean access(String ip) {
        // @todo
            return false;
        }
    }
package com.it.juxiang.demo.bool;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;


/**
 * 模拟同一用户快速多次登录(请求),通过(UserLoginLimiter)限制
 *
 */


@Controller
public class UserLoginTimeController {
    @Autowired
    private UserLoginLimiter userLoginLimiter;


    @PostMapping("/bool")
    @ResponseBody
    public String test() {
        String ip="192.168.198.10";
        if (userLoginLimiter.check(ip)) {
            System.out.println(ip + ":访问成功:true...........!");
            return (ip + ":访问成功:true!");
        } else {
            System.out.println(ip +":访问失败:false!");
            return (ip + ":访问失败:false!");
        }
    }
    
}
package com.it.juxiang.demo.bool;

import org.springframework.stereotype.Component;

import java.util.LinkedList;

/**
 * 用户登录记录限制类
 * 限制在一定时长(thresholdInMillisecond)内最多登录(maxLoginTimes)次
 */
@Component
public class UserLoginLimiter {
    //默认限制器,限制在60秒之内最多访问10次
    private int maxLoginTimes=10; //一定时间(thresholdInMillisecond值)内的最多登录次数
    private int thresholdInMillisecond=60000; //时长
    private LinkedList<LoginRecord> loginRecordList=new LinkedList<LoginRecord>(); //最近的登录队列



    /**
     * 检查登录记录,
     * 对在(thresholdInMillisecond)时长内超过(maxloginTimes)次的登录记录返回false,否则返回true;
     * @param ip
     * @return
     */
    public boolean check(String ip) {

        //检查设置的值,对0及负数表示不限制登录
        if (maxLoginTimes <= 0 || thresholdInMillisecond <= 0) return true;

        LoginRecord loginRecord=new LoginRecord(ip,System.currentTimeMillis());

        //队列长度未到maxLoginTimes的不用限制
        if (loginRecordList.size() < maxLoginTimes) {
            loginRecordList.addLast(loginRecord);
            return true;
        }

        //队列长度达到maxLoginTimes的,清理和当前记录比较超过thresholdInMillisecond值的记录
        LoginRecord firstLR = loginRecordList.getFirst();
        while (loginRecordList.size() > 0 && firstLR.getTime() + thresholdInMillisecond < loginRecord.getTime()) {
            loginRecordList.removeFirst();
            if (loginRecordList.size() > 0) {
                firstLR = loginRecordList.getFirst();
            } else {
                break;
            }
        }

        //检查队列是否有空间添加新的记录
        if (loginRecordList.size() < maxLoginTimes) {
            loginRecordList.addLast(loginRecord);
            return true;
        } else {
            return false; //队列中的记录与当前登录记录发生在thresholdInMillisecond内,拒绝
        }
    }

}
package com.it.juxiang.demo.bool;

/**
 * 用户登录记录类
 */
public class LoginRecord {
    private String ip;
    private long time;

    public LoginRecord(String ip, long time) {
        this.ip = ip;
        this.time = time;
    }

    public String getIp() {
        return ip;
    }

    public long getTime() {
        return time;
    }


    @Override
    public String toString() {
        return "LoginRecord{" +
                "ip='" + ip + '\'' +
                ", time=" + time +
                '}';
    }
}

 推荐一个软件,可以方便测试多线程下的运行:

Apache JMeter WEB

 

 

 

 

 

 

举报

相关推荐

0 条评论