目的
让用户访问某个接口时,限制一定时间只能访问N次
下面介绍后端的限制方法:
原理
服务器通过redis记录请求的次数,如果次数超过限制就不给访问。
设置redis 的key的时效性,过期自动销毁
自定义注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
@Documented @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD,ElementType.TYPE}) public @interface AccessLimit {
int seconds();
int maxCount();
}
|
配置拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| @Component public class LimitInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(LimitInterceptor.class);
@Autowired private RedisCache redisCache;
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class); if (accessLimit == null) { return true; } int seconds = accessLimit.seconds(); int maxCount = accessLimit.maxCount(); String key = request.getServletPath()+request.getSession().getId();
Integer count = 0; if (redisCache.getCacheObject(key) != null) { count = (Integer) redisCache.getCacheObject(key); }
if (count == 0) { redisCache.setCacheObject(key, 1); redisCache.expire(key, seconds, TimeUnit.SECONDS); logger.info("{}第一次访问",key); } else if (count < maxCount) { redisCache.incr(key, 1); } else { logger.error("超出访问次数"); render(response, "请求次数过于频繁!"); return false; } } return true; }
private void render(HttpServletResponse response, String msg) throws Exception { response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); out.print(new ObjectMapper().writeValueAsString(RespBean.error(msg))); out.flush(); out.close(); }
}
|
注册拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Configuration public class WebConfig implements WebMvcConfigurer { @Bean public LimitInterceptor limitHandlerInterceptor(){ return new LimitInterceptor(); }
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(limitHandlerInterceptor()); } }
|
在Controller的接口加上注解
1 2 3 4 5 6 7 8 9
| @PostMapping("/")
@AccessLimit(seconds = 6,maxCount = 1) public RespBean addEmp(@RequestBody Employee employee) { if (employeeService.addEmp(employee)) { return RespBean.ok("添加成功!"); } return RespBean.error("添加失败!"); }
|