华为面试:如何防止接口被刷百万QPS?

面试官:接口被恶意狂刷,怎么办? :这个……没搞过(每天 CRUD,真没搞过) 面试官:那你现在设计一个? :巴拉巴拉……(自己都不信的胡扯) 面试官:(明显不耐烦)那我们换个话题吧。

说实话,那一刻我就知道—— 这场面试,已经凉了一半。

不是我不会写代码, 而是我从没系统想过「接口防刷」这种问题

但后来我才发现一件事 接口防刷,其实一点都不复杂,甚至可以「一个注解搞定」

今天这篇,我不跟你扯高深架构, 就用一个能在面试里讲清楚、在项目里用得上的防刷方案, 让你下次被问到,至少能稳稳说出 123

-****01-

**接口防刷,本质在防什么? **

很多人一听“防刷”,脑子里就冒出:

  • 风控

  • 限流算法

  • 网关

  • 黑名单

  • 滑块验证

其实对 80% 的业务系统来说,根本用不上这么重。

我们今天解决的是最常见的一类问题:

同一个用户 / 同一个接口,在短时间内被疯狂请求

所以防刷的核心只有一句话:

限制「同一个人」在「同一个接口」上的访问次数

[图片上传失败...(image-83c807-1768211127894)]

-****02-

**一个注解搞定防刷 **

先别急着看代码,先把思路在脑子里跑通

整体设计思路(面试版)

  1. 用自定义注解标记哪些接口需要防刷

  2. 用拦截器统一拦截请求

  3. 用 Redis记录访问次数

  4. 超过阈值,直接拒绝

一句话就是:

注解定义规则,拦截器执行规则,Redis 负责记账

第一步:自定义一个防刷注解

我们先定义一个注解,用来描述「防刷规则」。

<pre data-start="974" data-end="1147" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">

@Retention(RUNTIME) @Target(METHOD) public @interface AccessLimit { // 允许访问的最大次数 intmaxCount(); // 是否需要登录 boolean needLogin()default false; }

</pre>

这个注解只干一件事:

把“防刷规则”写在方法上,而不是写死在代码里

用起来会非常优雅👇

<pre data-start="1203" data-end="1350" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">

@AccessLimit(maxCount = 5, needLogin = true) @RequestMapping("/fangshua") @ResponseBody public Object fangshua() { return"请求成功"; }

</pre>

第二步:Redis 负责「记账」

防刷一定绕不开 Redis。

我们需要它做的事情很简单:

  • key:请求标识

  • value:访问次数

  • TTL:有效期

Redis Key 设计(重点,面试加分)

<pre data-start="1485" data-end="1520" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">

URI + userId + yyyyMMdd

</pre>

也就是说:

同一个用户,在同一天,对同一个接口的访问次数

第三步:拦截器里干“脏活累活”

所有真正的防刷逻辑,都在拦截器里。

核心逻辑拆解(一定要能讲)

  1. 判断当前请求是否是 Controller 方法

  2. 判断方法上有没有 @AccessLimit

  3. 组装 Redis key

  4. 从 Redis 取访问次数

  5. 超限 → 直接拦截

核心代码(精简但完整)

<pre data-start="1750" data-end="3151" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">

@Component

</pre>

注册拦截器(别忘了这一步)

<pre data-start="3178" data-end="3455" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">

@Configuration public class WebConfigextends WebMvcConfigurerAdapter { @Autowired private FangshuaInterceptor interceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(interceptor); } }

</pre>

到这一步,防刷链路已经完整闭环了

效果验证

访问接口:

<pre data-start="3503" data-end="3541" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">

http://localhost:8080/fangshua

</pre>

  • 前 5 次:请求成功

  • 第 6 次:访问次数已达上限

一个注解,防刷生效。

[图片上传失败...(image-bf626e-1768211127894)]

-****03-

如果面试官继续追问,你可以这么答

Q1:这种方案适合什么场景?

适合中小系统、管理后台、业务接口级防刷 不适合超高并发网关级限流

Q2:有什么优化空间?

  • key 增加 IP 维度

  • 使用 Redis Lua 保证原子性

  • 与网关限流形成双层防护

Q3:为什么不用 AOP?

拦截器更贴近请求链路, AOP 更适合业务横切,不适合请求级控制

[图片上传失败...(image-916691-1768211127893)]

-****04-

总结

****接口防刷不是“高深架构”,而是“基础设计能力”****

你不需要一上来就说:

  • Sentinel

  • Gateway

  • 滑块验证码

你只要能把:

  • ****注解****

  • ****拦截器****

  • ****Redis****

  • ****Key 设计****

**这条链路讲清楚, **面试官就已经在心里给你加分了。****

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容