Laravel防重复提交推荐用Cache::add实现原子级去重中间件,构造IP+方法+路由+关键参数的唯一指纹,60秒有效期,返回425状态;也可按用户+路由做轻量锁或结合session简易幂等。

在 Laravel 中,用中间件防重复提交是高效、可复用的方案,核心思路是:**在请求进入控制器前,用缓存(如 Redis)或 session 标记该请求指纹,若已存在则直接拦截**。它不依赖前端行为,也不修改业务逻辑,适合统一管控多类表单接口。
用 Cache::add 实现原子级去重中间件
这是最推荐的方式,利用缓存驱动的原子写入特性(如 Redis 的 SETNX),确保并发请求中仅第一个能成功注册指纹。
- 构造唯一指纹:组合 IP、HTTP 方法、路由名、关键参数(如 user_id、order_type),避免只用时间戳或纯 URL
- 调用 Cache::add($fingerprint, true, 60),设置 60 秒有效期;返回 false 表示重复请求
- 拦截时返回 425 Too Early 或自定义 JSON 错误,语义清晰且利于前端识别重试逻辑
- 无需手动清理缓存——过期自动失效,无状态、无残留
按用户+路由维度做轻量锁中间件
适用于登录态明确、需限制同一用户短时间内重复操作的场景(如提交报名、发送通知),实现简单、兼容性好。
- 缓存键格式:'req_lock_' . $request->user()?->id . '_' . $request->route()->getName()
- 使用 Cache::has($key) 判断是否已有进行中的请求
- 若不存在,执行 Cache::put($key, now(), now()->addSeconds(30)) 并放行
- 注意:不适用于高并发秒杀类场景,因非原子操作可能有竞态风险
结合 session 做简易幂等中间件(适合单机部署)
不依赖 Redis,适合小流量或开发环境,但要注意 session 生命周期和 NAT 环境下的 IP 冲突问题。
- 指纹建议包含:$request->ip() . $request->userAgent() . $request->route()->getName() . md5(serialize($request->except('_token')))
- 用 session()->has('submit_fingerprint') && session('submit_fingerprint') === $fingerprint 判断
- 验证通过后立即 session(['submit_fingerprint' => $fingerprint]),业务完成后 session()->forget('submit_fingerprint')
- 慎用 flash 数据——它会在下个请求后自动清除,用户离开页面再回来易被误判为重复
中间件注册与使用建议
不要全局注册防重中间件,应按需绑定到具体路由或分组,避免影响健康检查、静态资源等无害请求。
- 在 app/Http/Kernel.php 中定义中间件别名,例如
'prevent-duplicate' - 在路由文件中精准应用:
Route::post('/orders', [OrderController::class, 'store'])->middleware('prevent-duplicate'); - 若用于 API,配合 throttle 中间件效果更佳,既控频次又保幂等
- 日志建议记录被拦截的指纹和 IP,便于排查误拦或攻击行为


















