本文共 2854 字,大约阅读时间需要 9 分钟。
在项目中,接口的暴露在外面,很多人就会恶意多次快速请求,那我们开发的接口和服务器在这样的频率下的话,服务器和数据库很快会奔溃的,那我们该怎么防止接口防刷呢?
其实也就是spring拦截器来实现。在需要防刷的方法上,加上防刷的注解,拦截器拦截这些注解的方法后,进行接口存储到redis中。当用户多次请求时,我们可以累积他的请求次数,达到了上限,我们就可以给他提示错误信息。
写一个注解
@Retention(RUNTIME)@Target(METHOD)public @interface AccessLimit { int seconds(); int maxCount(); boolean needLogin()default true;}
重点是写下面的拦截器
@Autowired private RedisService redisService;
@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(); boolean login = accessLimit.needLogin(); String key = request.getRequestURI(); //如果需要登录 if(login){ //获取登录的session进行判断 //..... key ="" "1"; //这里假设用户是1,项目中是动态获取的userId }
//从redis中获取用户访问的次数 AccessKey ak = AccessKey.withExpire(seconds); Integer count = redisService.get(ak,key,Integer.class); if(count == null){ //第一次访问 redisService.set(ak,key,1); }else if(count < maxCount){ //加1 redisService.incr(ak,key); }else{ //超出访问次数 render(response,CodeMsg.ACCESS_LIMIT_REACHED); //这里的CodeMsg是一个返回参数 return false; } }
return true;
} private void render(HttpServletResponse response, CodeMsg cm)throws Exception { response.setContentType("application/json;charset=UTF-8"); OutputStream out = response.getOutputStream(); String str = JSON.toJSONString(Result.error(cm)); out.write(str.getBytes("UTF-8")); out.flush(); out.close(); } } ```
@Configurationpublic class WebConfig extends WebMvcConfigurerAdapter { @Autowired private FangshuaInterceptor interceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(interceptor); }}
这样实现了具体的逻辑,我们可以在controller中使用这个注解了
@Controllerpublic class FangshuaController { @AccessLimit(seconds=5, maxCount=5, needLogin=true) @RequestMapping("/fangshua") @ResponseBody public Resultfangshua(){ return Result.success("请求成功"); }
这里采用了注解方式(拦截器),结合redis来存储请求次数,达到上限就不让用户操作。当然,redis有时间限制,到了时间用户可以再次请求接口的。欢迎关注
转载地址:http://xidsn.baihongyu.com/