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

下面是原本面试现场:

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

我:这个没搞过(每天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编程爱好者

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

相关推荐

小红书VS快手后端日常实习offer帮选offer1:快手电商,商品比价部门,base杭州,Java后端,听知情人说快手这个部门去年这个时候招了很多实习生,年后都跑路了(不好确定信息真实性)。我也不太了解比价业务,不知道会涉及到哪些场景,对个人成长是否有帮助。offer2:&nbsp;小红书AI数据引擎后端开发(应该算AI&nbsp;Infra方向,JD里描述:为大模型提供高效的多模态数据预处理引擎,构建高质量的AI数据迭代链路),base北京,也是Java为主,主要是工程,会涉及到一些大数据开发的技术栈,面试官给我的感觉比较靠谱,说技术深度会比较高,会考虑到实习生的成长性,不会安排dirty&nbsp;work。此外组内还有AI存储方向,对技术要求很高,有海量数据处理的场景,如果感兴趣的话,后续可能也有机会接触。主包个人情况:研一,28届,研二大概率没法实习了。1.&nbsp;一段美团的AIOps方向的后端实习(5个月),从0到1做的运维agent(已推广内部使用),tob,技术深度一般但不是杂活,Java为主,写的接口中也会用到消息队列和缓存这些。收获:对运维相关业务,故障排查,agent开发这些方面积累了很多经验2.&nbsp;一段小厂,Java,很水,业务需求,CRUD,稍微包装了一下,但从最近的面试来看,基本没人care。主包自己想法:实习目的还是为了校招能拿到一个更好的offer,不追求实习的数量,追求实习的质量。主包目前的实习都没有接触高并发的场景,感觉技术深度都比较浅。接下来的实习主包应该更看重一点技术深度还是好的业务。如果选择xhs这个AI数据引擎开发,校招时在投递大厂的核心业务部门会不会因为无相关的业务经验而比较吃亏。
黄同学在此:推荐小红书。研一就有俩实习经历,大概率本科去的吧?
offer帮选
点赞 评论 收藏
分享
01-14 10:23
已编辑
湖南师范大学 计调
太久没更新,前几天看到一条评论,说“牛客就是当年那群做题区毕业了开始找工作还收不住那股味”的群体。字里行间透着居高临下的评判,不是,他该不会以为自己很幽默?很犀利吧?作为在牛客混了不算短日子的用户,我感到的不只是被冒犯,更是一种深刻的悲哀——这种以“松弛感”为名,对另一种生存策略的轻蔑,颇有一种自己考不上大学早早出来混社会,嘲笑考上大学的人是书呆子,然后大言不惭地说:死读书有什么用,人脉和资源才是硬道理。我不知道说这个话的人,手头究竟握着多少真正管用的人脉与资源,也不知道他这么傲慢地说出“那股味”的时候,是站在哪一个巨人的肩膀上,才能如此“松弛从容”地俯视众生,还能品评出别人身上“没收住”的余...
淬月星辉:这种评论把正常的努力扭曲成卷😂,说白了就是自己不努力,看着身边努力的人一个个都事业有成了,自己的心里开始不平衡了,就发这种酸言酸语。牛客可以说是我用过那么多平台里社区氛围最好的论坛了,用了大半年了,基本上没见过有人吵架的,都是在互帮互助提建议,帮忙看简历的,帮忙选offer的,帮忙指点学习路线的,分享工作经验和趣事的,我觉得这才是互联网该有的样子。
点赞 评论 收藏
分享
评论
3
11
分享

创作者周榜

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