MVC中重定向时何时清空ViewBag以避免toastr消息重复显示
这个问题我之前也碰到过,核心原因是你选错了存储提示消息的容器——ViewBag的生命周期只限于单次请求,而且没办法自动清除状态,导致用户后退时(不管是缓存加载还是重新请求),消息会再次触发显示。下面给你几个靠谱的解决方案,按优先级来:
最佳方案:改用TempData存储消息
TempData是MVC专门为跨请求(比如重定向)传递临时数据设计的,它的特性是:数据会被保留到下一次请求读取后,自动标记为删除,完美适配你重定向后显示消息的场景。
代码修改步骤:
后端Action修改:把原来设置
ViewBag.Message的地方改成TempData["Message"]// 处理AJAX请求的Action [HttpPost] public ActionResult YourAjaxAction() { // 执行你的业务逻辑... // 设置跨重定向的提示消息 TempData["Message"] = "操作已成功完成"; // 重定向回原页面的Action return RedirectToAction("YourOriginalAction"); } // 原页面的Action(不需要额外设置消息) public ActionResult YourOriginalAction() { // 可选:如果需要强制页面不缓存,避免后退加载缓存页面 Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetNoStore(); return View(); }前端JS修改:把读取
ViewBag改成读取TempData$(document).ready(function () { var msg = "@TempData["Message"]"; if (msg.trim() != "") { toastr["success"](msg); } });
为什么这能解决问题?
当用户完成操作重定向到原页面时,TempData["Message"]会被读取并显示toastr,同时服务器会自动标记这个数据为删除。当用户后退时,要么浏览器重新请求原Action(此时TempData已经没有值了),要么如果浏览器缓存了页面,你可以通过上面的缓存设置强制重新请求,确保消息不会重复弹出。
备选方案:前端标记消息已显示
如果因为某些原因不能用TempData,可以在前端用sessionStorage标记消息是否已经显示过:
$(document).ready(function () { var msg = "@ViewBag.Message"; var messageKey = "toastr_" + msg.replace(/\s/g, "_"); // 生成唯一标识 if (msg.trim() != "" && !sessionStorage.getItem(messageKey)) { toastr["success"](msg); sessionStorage.setItem(messageKey, "shown"); } });
不过这个方案有个小缺点:如果用户清除了浏览器存储,或者换了设备,可能会有异常;而且如果消息内容重复,会误判为已经显示过,所以优先级不如TempData。
常见误区:为什么不能直接清空ViewBag?
你可能会想,能不能在显示消息后清空ViewBag?但ViewBag是服务器端的对象,前端显示消息时请求已经结束了,没办法在前端直接修改服务器端的ViewBag状态。就算你在后端Action里手动清空,也没办法覆盖浏览器缓存的页面内容,所以根本解决不了后退重复显示的问题。
内容的提问来源于stack exchange,提问作者TrevorGoodchild

