用户登录
用户注册

分享至

spring boot使用redis限制接口访问次数

  • 作者: 約啶啈冨19506237
  • 来源: 51数据库
  • 2021-10-30

首先自定义一个注解用于需要限制访问次数的接口

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

    //限制访问次数
    int limitCount() default 3;
    
    //超时时间
    long expireTime() default 60L;

    //请求url
    String requestUrl() default "";

}

切面用于执行具体的操作

@Component
@Aspect
public class RequestLimitAspect {

    @Autowired
    private RedisUtils redisUtils;

    @Pointcut("@annotation(requestLimit)")
    public void limit(RequestLimit requestLimit) {

    }

    @Around("limit(requestLimit)")
    public Object requestLimitLog(ProceedingJoinPoint joinPoint, RequestLimit requestLimit) throws Throwable {
        HttpServletRequest request = null;
        HttpServletResponse response = null;
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if(arg instanceof HttpServletRequest)
                request = (HttpServletRequest) arg;
            if(arg instanceof HttpServletResponse)
                response = (HttpServletResponse) arg;
        }
        if (request == null || response == null)
            return null;
        String sessionId = request.getSession().getId();
        String key = sessionId + requestLimit.requestUrl();
        long limitTime = requestLimit.expireTime();
        //从redis获取值
        Object requestCount = redisUtils.get(key);
        //首次访问初始化请求次数及过期时间,后续访问时判断请求次数是否超过限制次数
        if (requestCount == null) {
            redisUtils.set(key, 1, limitTime);
        } else if(Integer.valueOf(requestCount.toString()) >= requestLimit.limitCount()) {
            //超过限制次数返回对应枚举值
            LoginHandlerInterceptor.handlerErrorResponse(response, RetEnum.REQUEST_LIMITED);
            return null;
        } else {
            //更新访问次数及过期时间
            Integer count = Integer.valueOf(requestCount.toString()) + 1;
            redisUtils.set(key, count, limitTime);
        }
        return joinPoint.proceed(args);
    }

}

handlerErrorResponse方法用于返回错误信息

public static void handlerErrorResponse(HttpServletResponse response, RetEnum retEnum) throws Exception {
        response.setStatus(200);
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        try (PrintWriter writer = response.getWriter()) {
            String result = "{\"state\": \""
                    .concat(retEnum.getCode().toString())
                    .concat("\",\"msg\": \"")
                    .concat(retEnum.getMsg())
                    .concat("\"}");
            writer.write(result);
            writer.flush();
        } catch (Exception e) {
            throw new Exception("系统异常!");
        }
    }

RetEnum枚举

public enum RetEnum {
    /**
     * 请求被限制
     */
    REQUEST_LIMITED (1004,"请求被限制!"),
    private Integer code;
    private String msg;

    RetEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

Controller

@RestController
public class HelloController {

    @RequestLimit(requestUrl = "/hello")
    @RequestMapping("/hello")
    public String hello(@RequestParam String name, HttpServletRequest request, HttpServletResponse response) {
        return "Hello " + name;
    }
}

第1,2,3次执行结果

Hello test

第4次执行结果

{
    "state": "1004",
    "msg": "请求禁止!"
}
软件
前端设计
程序设计
Java相关