SpringBoot防止重复提交(2)
例如:多次点击提现按钮
问题描述:
在提现操作中,用户可能会多次点击提现按钮,导致多个相同的请求发送到服务器,从而引发重复提现的问题。为了解决这一问题,必须保证每个提现请求只能执行一次,防止重复提交操作。
两种常见的解决方案:
方案 1:基于浏览器页面打开的时候生成
Token
实现步骤:
生成唯一提现票据(Token)
逻辑:当用户进入提现页面时,后端生成一个唯一的
Token
(如UUID
)。该Token
会被存储到 Redis 中,并设置较短的有效期(如 5 秒)。返回给前端:后端将该
Token
返回给前端,前端每次提交提现请求时,必须携带该Token
。校验
Token
逻辑:每次提现请求时,后端会校验请求中的
Token
是否存在且未过期。
如果
Token
不存在或已失效,后端直接返回 "重复请求" 错误信息,拒绝继续处理。如果
Token
存在且未过期,后端继续处理提现请求,并将该Token
从 Redis 中删除,防止重复提交。适用场景:
适用于防止用户短时间内多次点击提现按钮的场景。
Token
的有效期较短,适用于需要快速防止重复请求的情况。优点:
简单易实现:只需在后端生成并校验
Token
,通过短期有效的Token
快速避免重复请求。避免短时间内的重复提交:有效防止用户因误操作或延迟导致的多次请求。
缺点:
有效期短:如果用户在 5 秒(或设置的短期有效期内)没有再次点击提现,
Token
会失效,导致无法继续提交请求。用户体验差:若用户长时间未操作,
Token
会过期,需要重新获取新的Token
。此时,如果用户未刷新页面,可能会导致不必要的操作中断,影响用户体验。假如说,如果遇到下面的问题呢:
用户在 5 分钟未点击操作,或者第一次点击后 5 分钟没有刷新页面,之后再次点击会失败。由于
Token
已过期,系统会认为是重复请求,导致用户无法继续提现。
方案 2:基于首次点击按钮才生成
Token
,并存储于前端实现步骤:
生成并存储
Token
逻辑:当用户首次点击提现按钮时,后端生成一个唯一的
Token
,并存储到 Redis 中(例如:5秒)。返回给前端:后端将该
Token
返回给前端,前端将其存储在浏览器(如localStorage
或sessionStorage或者请求头
)中。后续请求验证
Token
逻辑:每次用户点击提现按钮时,前端会从浏览器缓存中取出
Token
,并将其作为请求的一部分传递给后端。后端校验
Token
:
如果
Token
已存在,说明该请求是重复点击,拒绝继续执行,并提示用户:“您已提交提现请求,请等待处理”。如果
Token
不存在,说明是新的提现请求,后端重新生成并存储新的Token
,并继续处理提现请求。适用场景:
适合长时间有效的操作场景,特别是用户可能在较长时间内未刷新页面的情况下,系统仍然能够处理提现请求。
适用于长时间内防止重复提交问题。
优点:
避免
Token
过期问题:用户在打开浏览器页面后较长时间内可以随时提交提现请求,而不需要担心Token
过期。
因为不是打开页面创建的Token,是首次点击才创建Token
缺点:
依赖前端存储:需要依赖前端(如
localStorage
或sessionStorage
)来存储Token
,如果用户清除浏览器缓存或者使用隐私模式,可能导致Token
丢失。增加系统复杂度:需要保证前后端
Token
的同步,避免出现Token
被滥用的情况。