美团面试:接口被恶意狂刷,怎么办?

下面是原本面试现场:

面试官:接口被恶意狂刷,怎么办?

我:这个没搞过(每天CRUD,真的没搞过)

面试官:如果现在让你来设计,你会怎么设计?

我:巴拉巴拉...胡扯一通

面试官:(带着不耐烦的表情)我们还是换个话题吧

.....

为了不让大家也和我有同样的遭遇,今天,咱们就用一个非常简单的方式实现防刷:

一个注解搞定防刷

技术点

涉及到的技术点有如下几个:

  • 自定义注解
  • 拦截器
  • Redis的基本操作
  • Spring Boot项目

其实,非常简单,主要的还是看业务。

机-会

技术大厂,前端-后端-测试,全国均有机会,感兴趣可以试试。待遇和稳定性都还不错~

自定义注解

自定义一注解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配置项

在配置文件中,加入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中引入。

xml 体验AI代码助手 代码解读复制代码<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>

创建拦截器

创建拦截器,所有请求都进行拦截,防刷的主要内容全部在这里。

// 一堆import 这里就不贴出来了,需要的自己导入
/**
 *  处理方法上 有 AccessLimitEnum 注解的方法
 * @author java后端技术全栈
 * @date 2021/8/6 15:42
 */
@Component 
public class FangshuaInterceptor extends HandlerInterceptorAdapter {

    @Resource
    private RedisTemplate<String,Object> 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+日期。即Rediskey=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了。也建议大家手动试试,自己搞出来了更带劲儿。

——转载自:Java编程爱好者

#面试时最害怕被问到的问题#
全部评论
遇到刷接口的 就私聊他 告诉他求求你不要刷了
4 回复 分享
发布于 01-12 18:19 陕西
aop也行
点赞 回复 分享
发布于 01-12 21:25 浙江

相关推荐

01-14 10:23
已编辑
湖南师范大学 计调
太久没更新,前几天看到一条评论,说“牛客就是当年那群做题区毕业了开始找工作还收不住那股味”的群体。字里行间透着居高临下的评判,不是,他该不会以为自己很幽默?很犀利吧?作为在牛客混了不算短日子的用户,我感到的不只是被冒犯,更是一种深刻的悲哀——这种以“松弛感”为名,对另一种生存策略的轻蔑,颇有一种自己考不上大学早早出来混社会,嘲笑考上大学的人是书呆子,然后大言不惭地说:死读书有什么用,人脉和资源才是硬道理。我不知道说这个话的人,手头究竟握着多少真正管用的人脉与资源,也不知道他这么傲慢地说出“那股味”的时候,是站在哪一个巨人的肩膀上,才能如此“松弛从容”地俯视众生,还能品评出别人身上“没收住”的余...
淬月星辉:这种评论把正常的努力扭曲成卷😂,说白了就是自己不努力,看着身边努力的人一个个都事业有成了,自己的心里开始不平衡了,就发这种酸言酸语。牛客可以说是我用过那么多平台里社区氛围最好的论坛了,用了大半年了,基本上没见过有人吵架的,都是在互帮互助提建议,帮忙看简历的,帮忙选offer的,帮忙指点学习路线的,分享工作经验和趣事的,我觉得这才是互联网该有的样子。
点赞 评论 收藏
分享
1.第一种人呢以92和计算机强双非(四邮四电)偏多,这种人呢,喜欢把自己的学校称为“大专”,极力在交流时贬低自己的学历,放大自己学历的缺点(如牛客经典贴,双非秋招oc美团,点开发现是985硕士🤣🤣🤣),说的自己学校好像比双非认可度还低,好像这样才能突出自己多么牛逼,克服了多少困难,技术有多强,但你要是说想双非考研去他们学校,他们又要狠狠打压你,告诉考他们学校多难了🤣🤣🤣。从92到大厂明明是证明自己一直优秀的一条路,你不走,你非要故意恶心自己也恶心别人,何必呢?2.第二种人以像我一样的双非同学偏多,大多学历比较低,可能又带有中大厂实习。他们会在你交流的时候,十分刻意的强调自己是弱双非或者学院本,再不经意透露自己在某某大厂实习。等着群聊里响起“原来是xx(大厂名字)✌🏻啊,给你跪了😭”,他们便心满意足了。不用反驳,因为我之前也是这种人,现在也有这种倾向😆😆😆。3.第三种人更是神人,跟这种人交流时,你会觉得对方已经被美国植入芯片控制了,张嘴闭嘴只有膜膜膜,羡慕羡慕羡慕。上到拿到大厂offer,下到喝一杯奶茶,他们都说羡慕。不知道他们的生活过得有多么悲惨,连喝杯饮料都到了羡慕的地步🤣🤣🤣。天天就是在群里面互相吹捧,互相羡慕,不知道交流起来有什么意思。4.第四种人则是第一种人的对立面,我有时候觉得是第四种人太多才会导致第一种人的出现。这种人天生带着对92的恨。仿佛学计算机没有拿到offer全是92导致的。他们是小说里被陷害的白莲花女主,92则是夺走他们人生的恶毒女配。在他们的眼中,他们的技术要比92好一百倍,但是所有企业都识别不了他们这匹千里马。实际自己从来没想过,在ai与辅导课程普及的当日,所谓的计算机,早已经没有了任何的技术壁垒,否则也不会有那么人转码了😂。这是那天回家路上发抖音的,讨论不少,有赞同有不赞同的,其实有时候也在想自己言论是否偏激。今天遇到朋友问我好久没更新牛客了,就搬了上去。其实很简单,加了交流群之后,发现交流的质量参差不齐,有些实在言之无物,想了想自己也会有这样的问题。自己也在建交流群,希望能避免这样的现象吧
wu970:交流群不就是一群人互相装逼和加装谦虚吗
如何排解工作中的焦虑
点赞 评论 收藏
分享
评论
2
8
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务