⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7519769941501116479 「天天摸鱼的java工程师」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

一、前言

每到大型促销节点,比如双十一、618 或年终大促,秒杀活动就成了电商平台提升用户活跃度和销售额的重要手段。然而,这类高并发场景很容易被恶意用户刷接口导致服务雪崩、库存异常、甚至正常用户无法下单。

作为一名有 8 年 Java 开发经验的后端工程师,本文将从业务分析的角度出发,结合实战经验,带你一步步分析如何通过技术手段防止接口被刷,确保系统的稳定性和公平性。

二、业务痛点分析

1. 什么是刷接口?

刷接口是指通过程序自动化、高频率地请求秒杀接口,达到“抢占资源”的目的。常见表现包括:

  • 使用脚本/爬虫/自动化工具发起请求
  • 模拟并发请求进行库存占用
  • 利用代理 IP 规避限流
  • 利用账号批量注册参与秒杀

2. 秒杀的业务特点

  • 高并发: 短时间内请求量暴增,远超平时请求。
  • 低延迟要求: 用户希望秒杀结果快速返回。
  • 库存有限: 商品数量少,抢购激烈。
  • 公平性要求高: 若被刷接口,正常用户体验极差。

三、解决方案设计

我们可以从以下几个维度入手:

1. 接口层限流(Rate Limiting)

  • 利用 令牌桶算法 或 漏桶算法 实现接口访问限流。
  • 对不同用户/IP/设备设置访问频率限制。

2. 用户行为识别(风控)

  • 检测异常行为:如单 IP 高频请求、短时间内多次失败、多个账号来自同一 IP。
  • 加入风控拦截策略。

3. 接入验证码

  • 秒杀前加入图形验证码或滑动验证,防止机器人参与。
  • 使用行为验证码提高交互门槛。

4. 请求签名(防重放)

  • 在客户端请求中加入签名参数,签名内容包括时间戳、用户 ID、请求参数等,防止伪造请求。

5. 秒杀接口加固

  • 使用令牌机制(比如预先获取秒杀 token)
  • 使用消息队列异步下单
  • 控制库存扣减的原子性和幂等性

四、关键技术实现

下面我们以 Java 为例,逐步实现关键防刷逻辑。

1. 接口限流实现(基于令牌桶)

使用 Google 的 Guava RateLimiter:

private static final RateLimiter rateLimiter = RateLimiter.create(50); // 每秒最多 50 个请求

@GetMapping("/seckill")
public ResponseEntity<String> doSeckill(@RequestParam Long productId) {
if (!rateLimiter.tryAcquire()) {
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("请求过于频繁,请稍后再试");
}
// 进行秒杀逻辑
return ResponseEntity.ok("秒杀成功");
}

2. 用户请求签名校验

客户端请求加密签名,服务端校验:

public boolean checkSignature(String userId, String timestamp, String sign) {
String secret = "server_secret"; // 服务端秘钥
String raw = userId + timestamp + secret;
String expectedSign = DigestUtils.md5DigestAsHex(raw.getBytes());
return expectedSign.equals(sign);
}

3. 验证码防刷(简单图形验证码)

使用开源工具如 Kaptcha 生成图形验证码:

@GetMapping("/captcha")
public void getCaptcha(HttpServletResponse response, HttpSession session) throws IOException {
String captchaText = producer.createText();
session.setAttribute("captcha", captchaText);
BufferedImage image = producer.createImage(captchaText);
ImageIO.write(image, "jpg", response.getOutputStream());
}

在秒杀前验证验证码:

@PostMapping("/seckill")
public ResponseEntity<String> doSeckill(@RequestParam String captchaInput, HttpSession session) {
String realCaptcha = (String) session.getAttribute("captcha");
if (!captchaInput.equalsIgnoreCase(realCaptcha)) {
return ResponseEntity.badRequest().body("验证码错误");
}
// 继续处理秒杀逻辑
}

4. 异步下单 + 消息队列

使用 RabbitMQ/Kafka 解耦下单逻辑,避免接口被阻塞:

// 接口只发送消息
@PostMapping("/seckill")
public ResponseEntity<String> doSeckill(@RequestBody SeckillRequest request) {
if (!verifyToken(request.getToken())) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("非法请求");
}
mqSender.send("SECKILL_QUEUE", request);
return ResponseEntity.ok("请求已受理");
}

消费者监听队列,处理真实下单逻辑:

@RabbitListener(queues = "SECKILL_QUEUE")
public void handleSeckill(SeckillRequest request) {
// 检查库存、扣减、生成订单
}

五、防刷策略组合建议

策略类型 推荐级别 说明
限流 ★★★★★ 最基础也最有效
验证码 ★★★★☆ 提高门槛,防机器人
风控识别 ★★★★☆ 检测异常行为
请求签名 ★★★☆☆ 防止伪造请求
异步下单 ★★★★★ 降低接口压力,提高成功率

六、总结与展望

防止刷接口是一个系统性工程,需要从 “前端拦截 + 中间限流 + 后端加固 + 异常行为识别” 多维度配合。没有银弹,只有组合拳才能真正保障系统的稳定与公平。

文章目录
  1. 1. 一、前言
  2. 2. 二、业务痛点分析
    1. 2.0.1. 1. 什么是刷接口?
    2. 2.0.2. 2. 秒杀的业务特点
  • 3. 三、解决方案设计
    1. 3.0.0.1. 1. 接口层限流(Rate Limiting)
    2. 3.0.0.2. 2. 用户行为识别(风控)
    3. 3.0.0.3. 3. 接入验证码
    4. 3.0.0.4. 4. 请求签名(防重放)
    5. 3.0.0.5. 5. 秒杀接口加固
  • 4. 四、关键技术实现
    1. 4.0.1. 1. 接口限流实现(基于令牌桶)
    2. 4.0.2. 2. 用户请求签名校验
    3. 4.0.3. 3. 验证码防刷(简单图形验证码)
    4. 4.0.4. 4. 异步下单 + 消息队列
  • 5. 五、防刷策略组合建议
  • 6. 六、总结与展望