SpringBoot+Redis实现接口限流
1.redis接口限流注解
定义一个注解标明需要使用限流的接口
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AccessLimit {
/**
* @return 单位时间(秒)
*/
int seconds();
/**
* @return 单位时间最大请求次数
*/
int maxCount();
}
2.配置拦截器
在springboot的拦截器中,如果你没有配置拦截器,需要自定义类继承HandlerInterceptor,
@Log4j2
public class WebSecurityHandler implements HandlerInterceptor {
@Autowired
private RedisService redisService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
//如果请求输入方法
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
//获取方法中的注解,看是否有该注解
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
if (accessLimit != null) {
long seconds = accessLimit.seconds();
int maxCount = accessLimit.maxCount();
//关于key的生成规则可以自己定义 本项目需求是对每个方法都加上限流功能,如果你只是针对ip地址限流,那么key只需要只用ip就好
String key = IpUtils.getIpAddress(httpServletRequest) + hm.getMethod().getName();
//从redis中获取用户访问的次数
try {
//此操作代表获取该key对应的值自增1后的结果
long q = redisService.incrExpire(key, seconds);
if (q > maxCount) {
render(httpServletResponse, Result.ok(null, "请求过于频繁,请稍候再试"));
log.warn(key + "请求次数超过每" + seconds + "秒" + maxCount + "次");
return false;
}
return true;
} catch (RedisConnectionFailureException e) {
log.warn("redis错误: " + e.getMessage());
return true;
}
}
}
return false;
}
private void render(HttpServletResponse response, Result<?> result) throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
String str = JSON.toJSONString(result);
out.write(str.getBytes("UTF-8"));
out.flush();
out.close();
}
}
3.测试注解
@AccessLimit(seconds = 10, maxCount = 2)
访问受限测试

redis信息

后台打印信息
