laravel中可用四种缓存去重法:一、cache::add原子校验指纹;二、用户+路由+时间窗轻量锁;三、缓存标签批量失效;四、封装可配置中间件。

如果您在 Laravel 应用中频繁收到语义相同、参数一致的重复请求(如连点提交、前端重试未拦截、爬虫误刷等),则可能造成不必要的资源消耗与业务异常。以下是利用缓存机制实现请求去重的多种方法:
一、使用 Cache::add 实现原子性请求指纹校验
该方法依赖缓存驱动的原子写入特性,确保仅首个请求能成功注册指纹,后续并发请求因写入失败而被拦截,从根本上避免“缓存击穿”导致的重复执行。
1、在中间件或控制器入口处,构造唯一请求指纹,例如:md5($request->ip() . $request->method() . $request->fullUrl() . serialize($request->except('_token')))。
2、调用 Cache::add($fingerprint, true, 60) 尝试写入有效期为 60 秒的标记。
3、若返回 false,说明该指纹已存在,立即中止流程并返回 abort(429, 'Duplicate request detected')。
4、若返回 true,则允许请求继续执行,并在业务逻辑完成后无需额外清理——缓存将自动过期。
二、基于用户+路由+时间窗口的轻量级锁机制
该方法适用于登录用户场景,通过固定结构的缓存键实现粗粒度去重,不依赖原子操作,兼容文件驱动但需注意并发风险。
1、构造缓存键:'req_lock_' . $request->user()?->id . '_' . $request->route()->getName()。
2、使用 Cache::has($key) 检查是否存在。
3、若存在,直接响应 response(['message' => 'Request in progress'], 425)。
4、若不存在,执行 Cache::put($key, time(), now()->addSeconds(30)) 并继续处理请求。
三、结合缓存标签实现批量请求失效控制
当某类请求需在特定业务事件(如用户资料更新、库存变更)后统一失效时,可借助缓存标签对多个指纹键进行分组管理,提升维护效率。
1、在写入指纹时使用带标签的缓存操作:Cache::tags(['form_submit', 'user_' . $request->user()?->id])->put($fingerprint, true, 120)。
2、在用户资料更新完成后的事件监听器中,调用 Cache::tags(['form_submit', 'user_' . $userId])->flush() 清除全部关联指纹。
3、确保所选缓存驱动为 Redis 或 Memcached,因文件驱动不支持缓存标签功能。
四、封装为可复用的去重中间件
将指纹生成与缓存校验逻辑抽离为独立中间件,便于全局注册或按需启用,同时支持配置化参数(如有效期、是否忽略查询参数等)。
1、创建中间件类 App\Http\Middleware\PreventDuplicateRequests,在 handle 方法中注入 CacheInterface。
2、从中间件构造函数或配置文件读取策略参数:'ttl' => 45, 'ignore_query' => true, 'include_body' => false。
3、依据配置动态生成指纹,并执行 Cache::add($key, 1, $ttl) 原子写入。
4、校验失败时抛出 HttpResponseException 并返回标准化 JSON 错误响应。











