Spring Boot REST接口幂等校验需在服务端实现,主流方案有四种:1. Token令牌机制(推荐下单/支付),2. 数据库唯一索引(适用于新增操作),3. Redis请求摘要(适合参数固定的接口),4. 乐观锁+状态机(适用于状态变更类接口)。

Spring Boot 中 REST 接口实现幂等校验,核心是让同一请求多次到达时,业务逻辑只执行一次,后续调用直接返回历史结果。这不是靠前端按钮禁用或网络层拦截能解决的,必须在服务端做识别和控制。下面四种主流方案,按适用场景和落地难度展开说明。
Token 令牌机制(推荐用于下单、支付类接口)
客户端先申请一个一次性令牌,携带进业务请求;服务端验证并删除该令牌,确保它只能被消费一次。
- 服务端提供
/api/token接口,生成 UUID 并存入 Redis,设置 5–15 分钟过期 - 业务接口(如
POST /api/order)从 Header(如Idempotent-Token)中读取 token - 用 Lua 脚本原子性地判断 key 是否存在并删除:
if redis.call("exists", KEYS[1]) == 1 then return redis.call("del", KEYS[1]) else return 0 end - 若脚本返回 0,说明 token 不存在或已被使用,直接返回
409 Conflict或业务提示
数据库唯一索引(适合插入型操作,如创建支付记录)
利用数据库约束天然拒绝重复数据,简单高效,但仅适用于“新增”且有明确唯一标识的场景。
- 在表中添加唯一字段,例如
pay_record表增加unique(order_no, pay_channel_id) - 插入前不查库,直接执行 INSERT,捕获
DuplicateKeyException - 在全局异常处理器中统一转换为
Result.fail("操作已存在"),避免暴露数据库细节 - 注意:不能用于更新类操作,也不适合需要前置校验逻辑(如余额检查)的流程
Redis 请求摘要(适合参数固定、无敏感字段的接口)
对请求参数做哈希(如 MD5 或 SHA-256),以摘要值为 key 存入 Redis,有效期与业务时效匹配。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 提取关键参数(如 userId + orderId + amount + timestamp),拼接后计算摘要
- key 命名建议:
idempotent:pay:{hash},设置 30 分钟过期 - 拦截器中校验 key 是否存在,存在则跳过业务执行,直接返回上一次成功响应(需配合结果缓存)
- 优势是无需客户端配合发 token;缺点是参数变动即视为新请求,且哈希碰撞概率虽低但需兜底
乐观锁 + 状态机(适合状态变更类接口,如支付回调、订单发货)
不是阻止重复,而是让重复操作“安全失效”,依赖版本号或状态流转规则控制更新行为。
- 订单表加
version字段或status字段(如 UNPAID → PAID → SHIPPED) - 更新 SQL 加条件:
UPDATE order SET status = 'PAID', version = version + 1 WHERE order_no = ? AND status = 'UNPAID' AND version = ? - 根据
updateCount判断是否真正更新成功;为 0 则说明状态已变,本次请求无副作用 - 配合日志记录和补偿机制,可追溯重复触发源头(如支付平台重试)
不复杂但容易忽略的是:所有方案都要考虑失败回滚时 token 或摘要的恢复问题。比如 token 校验通过后业务执行失败,应把 token 重新写回 Redis(带稍短过期时间),否则用户重试会直接被拒。实际选型时,优先看操作类型——新增用唯一索引,变更用乐观锁,交互强的前端流程用 Token,参数稳定的服务间调用可用摘要。










