下面是原本面试现场:

面试官:接口被恶意狂刷,怎么办?
我:这个没搞过(每天CRUD,真的没搞过)
面试官:如果现在让你来设计,你会怎么设计?
我:巴拉巴拉...胡扯一通
面试官:(带着不耐烦的表情)我们还是换个话题吧
.....
为了不让大家也和我有同样的遭遇,今天,咱们就用一个非常简单的方式实现防刷:
一个注解搞定防刷
涉及到的技术点有如下几个:
其实,非常简单,主要的还是看业务。
本文主要内容:
自定义一注解AccessLimit。
- import java.lang.annotation.Retention;
 - import java.lang.annotation.Target;
 - import static java.lang.annotation.ElementType.METHOD;
 - import static java.lang.annotation.RetentionPolicy.RUNTIME;
 - @Retention(RUNTIME)
 - @Target(METHOD)
 - public @interface AccessLimit {
 - //次数上限
 - int maxCount();
 - //是否需要登录
 - boolean needLogin()default false;
 - }
 
在配置文件中,加入Redis配置;
- spring.redis.database=0
 - spring.redis.host=127.0.0.1
 - spring.redis.port=6379
 - spring.redis.jedis.pool.max-active=100
 - spring.redis.jedis.pool.max-idle=100
 - spring.redis.jedis.pool.min-idle=10
 - spring.redis.jedis.pool.max-wait=1000ms
 
注意,把Redis的starter在pom中引入。
org.springframework.boot spring-boot-starter-data-redis 
创建拦截器,所有请求都进行拦截,防刷的主要内容全部在这里。
- // 一堆import 这里就不贴出来了,需要的自己导入
 - /**
 - * 处理方法上 有 AccessLimitEnum 注解的方法
 - * @author java后端技术全栈
 - * @date 2021/8/6 15:42
 - */
 - @Component
 - public class FangshuaInterceptor extends HandlerInterceptorAdapter {
 - @Resource
 - private RedisTemplate
 redisTemplate; - @Override
 - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 - System.out.println("----FangshuaInterceptor-----");
 - //判断请求是否属于方法的请求
 - if (handler instanceof HandlerMethod) {
 - HandlerMethod hm = (HandlerMethod) handler;
 - //检查方法上室友有AccessLimit注解
 - AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
 - if (accessLimit == null) {
 - return true;
 - }
 - //获取注解中的参数,
 - int maxCount = accessLimit.maxCount();
 - boolean login = accessLimit.needLogin();
 - String key = request.getRequestURI();
 - //防刷=同一个请求路径+同一个用户+当天
 - //如果需要登录
 - if (login) {
 - //可以充session中获取user相关信息
 - //这里的userId暂时写死,
 - Long userId = 101L;
 - String currentDay = format(new Date(), "yyyyMMdd");
 - key += currentDay + userId;
 - }else{
 - //可以根据用户使用的ip+日期进行判断
 - }
 - //从redis中获取用户访问的次数
 - Object countCache = redisTemplate.opsForValue().get(key);
 - if (countCache == null) {
 - //第一次访问,有效期为一天
 - //时间单位自行定义
 - redisTemplate.opsForValue().set(key,1,86400, TimeUnit.SECONDS);
 - } else{
 - Integer count = (Integer)countCache;
 - if (count < maxCount) {
 - //加1
 - count++;
 - //也可以使用increment(key)方法
 - redisTemplate.opsForValue().set(key,count);
 - } else {
 - //超出访问次数
 - render(response, "访问次数已达上限!");
 - return false;
 - }
 - }
 - }
 - return true;
 - }
 - //仅仅是为了演示哈
 - private void render(HttpServletResponse response, String msg) throws Exception {
 - response.setContentType("application/json;charset=UTF-8");
 - OutputStream out = response.getOutputStream();
 - out.write(msg.getBytes("UTF-8"));
 - out.flush();
 - out.close();
 - }
 - //日期格式
 - public static String format(Date date, String formatString) {
 - if (formatString == null) {
 - formatString = DATE_TIME_FORMAT;
 - }
 - DateFormat dd = new SimpleDateFormat(formatString);
 - return dd.format(date);
 - }
 - }
 
注意
判断是否为相同请求,使用:URI+userId+日期。即Redis的key=URI+userId+yyyyMMdd,缓存有效期为一天。
很多都在代码里有注释了,另外强调一下,不要吐槽代码,仅仅是演示。
尽管上面我们已经自定义并实现好了拦截器,但还需要我们手动注册。
- import com.example.demo.ExceptionHander.FangshuaInterceptor;
 - import org.springframework.beans.factory.annotation.Autowired;
 - import org.springframework.context.annotation.Configuration;
 - import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 - import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 - @Configuration
 - public class WebConfig extends WebMvcConfigurerAdapter {
 - @Autowired
 - private FangshuaInterceptor interceptor;
 - @Override
 - public void addInterceptors(InterceptorRegistry registry) {
 - registry.addInterceptor(interceptor);
 - }
 - }
 
这样我们的注解就正式注册到拦截器链中了,后面项目中才会有效。
前面的准备都搞定了,现在来具体使用。
首先,我们创建一个简单的controller,然后,在方法上加上我们自定义的注解AccessLimit,就可以实现接口防刷了。
- import com.example.demo.result.Result;
 - import org.springframework.stereotype.Controller;
 - import org.springframework.web.bind.annotation.RequestMapping;
 - import org.springframework.web.bind.annotation.ResponseBody;
 - @Controller
 - public class FangshuaController {
 - //具体请求次数由具体业务决定,以及是否需要登录
 - @AccessLimit(maxCount=5, needLogin=true)
 - @RequestMapping("/fangshua")
 - @ResponseBody
 - public Object fangshua(){
 - return "请求成功";
 - }
 - }
 
测试,浏览器页面上访问:http://localhost:8080/fangshua
前面4次返回的是:请求成功
超过4次后变成:访问次数已达上限!
一个注解就搞定了,是不是 so easy !!!
关于接口防刷,如果在面试中被问到,至少还是能说个123了。也建议大家手动试试,自己搞出来了更带劲儿。
                当前文章:接口被恶意狂刷,怎么办?
                
                转载源于:http://www.csdahua.cn/qtweb/news0/453500.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网