ASP.NET 5 MVC表单重复提交(ERR_CACHE_MISS)问题及回退页面时提交对象恢复需求
嘿,你的这两个问题其实在ASP.NET MVC里有成熟的解决方案——用Post/Redirect/Get (PRG) 设计模式搭配TempData就能同时搞定表单重复提交和返回页面的状态恢复,我给你一步步拆解:
解决方案:PRG模式+TempData实现无重复提交与状态恢复
1. 解决Checkout页面刷新的表单重复提交问题(ERR_CACHE_MISS)
你现在的Booking表单直接提交到Checkout的Index Get方法,虽然当下能拿到数据,但如果后续业务需要提交更多复杂数据(或者实际用了Post提交),刷新页面就会触发浏览器的“Confirm Form Resubmission”提示——这是因为浏览器会保留Post请求的内容,刷新时会尝试重新发送。
PRG模式的核心思路是:用Post接收提交的数据,处理完后重定向到Get页面。这样浏览器地址栏最终是Get请求,刷新时只会重新发起Get,不会有重复提交的问题。
具体修改步骤:
- 更新Booking视图的表单:明确指定
method="post",提交到Checkout的一个新Post Action(比如叫PrepareCheckout),而不是直接到Index:<form asp-controller="Checkout" asp-action="PrepareCheckout" method="post"> <input hidden value="@Model.CarId" name="carId"> <input type="submit" value="Proceed"> </form> - 在Checkout控制器中新增
PrepareCheckoutPost Action:这里接收Booking传来的参数,把需要保留的对象存入TempData(后面返回Booking时要用),然后重定向到IndexGet页面:[HttpPost] public async Task<IActionResult> PrepareCheckout(int carId) { // 这里可以根据carId补全CarsBookingVM的其他字段,比如从数据库拉取车辆信息 var carsBooking = new CarsBookingVM { CarId = carId }; // TempData只能存基础类型或可序列化对象,所以先序列化 TempData["PreviousBooking"] = JsonSerializer.Serialize(carsBooking); // 重定向到Checkout的Index Get方法,彻底避免Post刷新问题 return RedirectToAction(nameof(Index), new { carId }); } - 保留原Checkout的
IndexGet方法:现在这个页面是通过重定向过来的,刷新时只会发起Get请求,再也不会弹出重复提交的提示了。
2. 实现从Checkout返回Booking时恢复之前的提交对象
当用户在Checkout页面点击返回按钮时,我们可以从之前存在TempData里的对象恢复状态,传递给Booking的页面。
具体修改步骤:
- 在Checkout视图中添加返回按钮:可以用链接或者表单,指向Booking的
Index方法:<a asp-controller="Booking" asp-action="Index">Back to Booking</a> - 修改Booking控制器的
Index方法:让它优先从TempData读取之前保存的对象,如果没有再用传入的参数或默认对象:public async Task<IActionResult> Index(CarsBookingVM carsBooking) { // 如果传入的参数为空,尝试从TempData恢复之前的提交对象 if (carsBooking == null || carsBooking.CarId == 0) { if (TempData.ContainsKey("PreviousBooking")) { var serializedBooking = TempData["PreviousBooking"].ToString(); carsBooking = JsonSerializer.Deserialize<CarsBookingVM>(serializedBooking); // 如果需要用户多次返回都能恢复状态,就把数据重新存回TempData TempData["PreviousBooking"] = serializedBooking; } } return View(carsBooking); }
额外注意点
- TempData的生命周期:默认情况下,
TempData里的数据被读取后会被标记为删除,下次请求就没了。如果需要多次使用,可以用TempData.Keep("PreviousBooking")或者像上面那样重新存入数据。 - 对象序列化:确保你的
CarsBookingVM类是可序列化的(比如有公共无参构造函数,字段都是可序列化类型),不然JsonSerializer会报错。 - Session替代方案:如果需要数据在用户会话中保留更长时间,可以用
ISession存储,但TempData更适合这种跨一次重定向的场景,因为它会自动清理,不会占用多余内存。
这样改完之后,两个问题都能解决:Checkout页面刷新不会再出现重复提交提示,返回Booking页面时也能恢复用户之前提交的对象状态。
内容的提问来源于stack exchange,提问作者Jbtf
相关产品推荐
相关产品推荐

