java 限制接口调用频率处理

1.创建注解

package com.kova.api.limit;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {

    long time() default 5000; //time是调用接口的间隔时间,默认是 5000 毫秒。
}

2.创建允许访问判断类

package com.kova.api.limit;

import java.util.concurrent.ConcurrentHashMap;

public class RequestLimiter {

    private  ConcurrentHashMap<String,Long> requestMap = new ConcurrentHashMap<>();

    private static volatile RequestLimiter instance;

    private RequestLimiter() {}

    public static RequestLimiter getInstance() {
        if (instance == null) {
            synchronized (RequestLimiter.class) {
                if (instance == null) {
                    instance = new RequestLimiter();
                }
            }
        }
        return instance;
    }
    //接口访问判断
    public boolean allowRequest(String userId,long timeLimit) {
        Long lastRequestTime = requestMap.get(userId);
        long currentTime = System.currentTimeMillis();
        if (lastRequestTime == null || (currentTime - lastRequestTime) > timeLimit)
        { // 允许请求并更新请求时间
             requestMap.put(userId, currentTime);
             return true;
        }
        return false; // 拒绝请求
     }
}

3.创建aop处理类

package com.kova.api.limit;

import com.kova.api.common.Result;
import com.kova.api.common.ResultEnum;
import com.kova.api.exception.CommonException;
import com.kova.api.utils.IpUtil;
import com.kova.api.verify.ParamsVerify;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

//限制接口调用频率处理
@Aspect
@Component
@Slf4j
public class RequestLimitAspect {

    @Synchronized // 作用是创建一个互斥锁,保证只有一个线程对 RequestLimiter.getInstance() 这个变量进行修改。
    @Around("execution(* com.kova.api.controller..*.*(..)) && @annotation(nrs)") // 这里要根据自己项目中的controller包路径来配置好
    public Object arround(ProceedingJoinPoint pjp, RequestLimit nrs) throws Throwable {

        if(nrs == null){
            return  pjp.proceed();
        }
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Object[] args = pjp.getArgs();
        String key = IpUtil.getIpAddr(request) + " :" + request.getServletPath();
        Long time = nrs.time();
        Object o = null;

        //可以改为redis保存处理
       if(RequestLimiter.getInstance().allowRequest(key,time)){
           o = pjp.proceed();
           return o;
       }else{
           log.error("操作过于频繁 {}", key);
           return Result.failed(ResultEnum.REQUEST_LIMIT);
       }

    }

}

4.创建controller类,添加测试方法

package com.kova.api.controller;

import com.kova.api.common.Result;
import com.kova.api.common.ResultEnum;
import com.kova.api.limit.RequestLimit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Slf4j
@RestController
@RequestMapping("/api/user")
public class UserController {

    /**
     * 接口频率访问测试
     *
     * 测试: curl http://localhost:8080/api/user/limit -X POST  -H "Content-Type:application/json" -d '{"name":"kingboyrang"}'
     * 
     *
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/limit", method = RequestMethod.POST)
    @RequestLimit //接口频率访问时间设置,默认值为5000
    //@RequestLimit(time = 1000) //接口频率访问时间设置
    public Result getReuqestLimitInfo(@RequestBody Map<String,Object> params){
        Map<String, Object> resultParams = new HashMap<String, Object>();
        resultParams.put("info", "接口访问限制测试");
        return Result.ok(resultParams);
    }
    
}

5.测试

curl http://localhost:8080/api/user/limit -X POST  -H "Content-Type:application/json" -d '{"name":"kingboyrang"}'
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
悠哉生活的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容