You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVC5 POST接口每周偶发同一用户同时两次调用的异常排查问题

问题描述

现有一套基于C#开发的MVC5 Web应用,运行稳定,支持10用户并发开具发票,每周会出现一次异常:同一用户同一时间发起两次POST请求,生成重复发票。

  • 已排除用户双击按钮:已实现按钮点击后立即禁用,服务端返回后才重新启用的逻辑
  • 已排除HTTP2影响:两周前已关闭IIS的HTTP2功能,异常仍发生
  • 日志特征:两次请求完全一致,第一次耗时9002ms,第二次耗时444ms,接口正常耗时不足1秒,异常发生时存在网络波动
2021-09-22 16:21:41 167.86.95.177 POST /Sales/Invoices/Save - 443 jnamicela 45.225.105.89 Mozilla/5.0+(Windows+NT+6.3;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/93.0.4577.82+Safari/537.36 https://xpertdynamics.com/Home/Index 200 0 1236 9002
2021-09-22 16:21:41 167.86.95.177 POST /Sales/Invoices/Save - 443 jnamicela 45.225.105.89 Mozilla/5.0+(Windows+NT+6.3;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/93.0.4577.82+Safari/537.36 https://xpertdynamics.com/Home/Index 200 0 0 444
根本原因分析
  • TCP协议层自动重传:这是最高概率的原因。当客户端第一次发送的POST请求已经成功送达服务端,但服务端返回的ACK确认包在公网传输时丢失,客户端在超时窗口内未收到确认信息,会由操作系统内核的TCP协议栈自动重传完全相同的请求包,整个过程不经过上层JS逻辑,所以前端的按钮禁用逻辑完全拦截不到,普通的网络延迟模拟也很难复现「请求到端、回包丢失」的特定场景。日志中第一次请求耗时远高于正常值,就是因为双方在等待TCP重传的超时窗口期。
  • 代理/网关层自动重试:如果用户侧有VPN、运营商代理,或者服务端有WAF、反向代理等中间层,部分中间件会默认对超时未返回的POST请求发起自动重试,也会产生完全相同的重复请求,和用户操作、前端逻辑无关。
彻底解决方案

核心方案:实现全链路幂等控制

这是唯一能覆盖所有重试场景的根因解决方案,不受上层操作、中间层、传输层行为影响:

  1. 页面加载阶段:用户进入发票开具页面时,服务端生成全局唯一的幂等Token,和当前用户身份绑定后返回给前端,存储在表单隐藏域或页面内存中。
  2. 请求提交阶段:前端将该Token作为请求的固定参数一起传给/Sales/Invoices/Save接口。
  3. 服务端处理逻辑:
    • 收到POST请求后,首先校验当前用户的该幂等Token是否已经存在处理成功的记录(可存储在Redis中,设置24小时过期即可,无需永久留存)
    • 若已存在记录,直接返回上次开具成功的结果,不执行重复业务逻辑
    • 若不存在记录,正常执行发票开具逻辑,处理完成后将Token和处理结果绑定存入缓存

兜底优化

业务字段校验(比如校验同一用户短时间内是否提交了完全相同的发票核心信息)可作为兜底逻辑,避免极端场景下的重复数据生成。

内容的提问来源于stack exchange,提问作者Steven Ochoa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 02:24:03