接口限流-使用Redis实现接口限流

发布时间 2023-06-16 15:16:37作者: 小羊爱吃草!

代码案列

 配置Redis

@Slf4j
@Configuration
@EnableCaching // 开启缓存支持
public class RedisConfiguration extends CachingConfigurerSupport {

    /**
     * RedisTemplate配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(getJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(getJackson2JsonRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    private Jackson2JsonRedisSerializer<Object> getJackson2JsonRedisSerializer() {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        return jackson2JsonRedisSerializer;
    }
}

  

创建注解

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

    添加拦截器  

@Slf4j
@Component
public class IpLimitInterceptor implements HandlerInterceptor {

@Autowired
private RedisTemplate<String,String> redisTemplate;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod;
try {
handlerMethod = (HandlerMethod) handler;
} catch (Exception e) {
this.checkFailResponse(response , "请求资源不存在");
return false;
}
//获取类上的注解 获取方法上注解
IpLimit ipLimit = handlerMethod.getBeanType().getAnnotation(IpLimit.class)==null?handlerMethod.getMethodAnnotation(IpLimit.class):handlerMethod.getBeanType().getAnnotation(IpLimit.class);
if(ipLimit==null){
return true;
}else{
//获取请求ip
String remoteAddr = request.getRemoteAddr();
//设置key ,key = 方法名 + ip地址,如果是想改成规定时间请求接口总数为5次,不加方法名即可
String key =handlerMethod.getMethod().getName()+":"+remoteAddr;
String s = redisTemplate.opsForValue().get(key);
log.info("ip limit key : {}",key);
if(ObjectUtil.isNotEmpty(s) && Integer.parseInt(s) >= 5){
this.checkFailResponse(response , "请求资源过于频繁,请稍后再试");
return false;
} else {
if(ObjectUtil.isEmpty(s)){
redisTemplate.opsForValue().set(key , String.valueOf(1), 10 , TimeUnit.SECONDS);
}else {
redisTemplate.opsForValue().set(key , String.valueOf(Integer.parseInt(s)+1), 10 , TimeUnit.SECONDS);
}
return true;
}
}
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

}

private void checkFailResponse(HttpServletResponse response , String message) throws Exception{
response.setHeader("Content-Type","application/json;charset=utf-8");
response.getWriter().print(message);
response.getWriter().flush();
}
}


将注解添加到接口或者接口类即可