思路:
重復提交有兩方面的含義,
一是操作方面的重復提交,旨在說明一個客戶端,一次只能發送一個請求到服務端,如果發出后未收到服務端響應,再次提交,則視為無效提交(重復了)。
二是業務方面,同一個表單,服務端處理了兩次,兩次都是合法的操作(不違反第一種含義),但是表單可能被處理了兩次,如像一個賬號轉賬了兩次,金額信息一致,可能后台的交易流水不一致,但是確實產生了兩筆交易。
在web項目中,防止重復提交,需要解決以上兩種問題,
第一種的解決思路是通過token的思路。
第二種通過業務判斷解決
以下部分代碼,首先服務端
表單提交前,或者表單加載時,服務端返回客戶端token
Session["LAST_TOKEN"] = token;
服務端接收客戶端發來的token,同時產生並、注冊、返回新的token 以便下次請求使用
string token = Guid.NewGuid().ToString(); if (Session["LAST_TOKEN"] == null || Session["LAST_TOKEN"].ToString() != submitToken) { Session["LAST_TOKEN"] = token; return Json(new { isSuccess = false, message = "提交失敗,可能是以下原因導致的:<br/> 1.點擊頻繁或按鍵失靈。<br/>2.頁面長時間未操作。<br/><font color=\"red\">如已出票,請忽略此消息!未出票,請重試!</font>", code = 510, token }); } Session["LAST_TOKEN"] = token;
以上方式,可解決問題一
下面的方式,解決問題二
Result<string> verfiyResult = this.FilterDuplicateOrderSubmit(bill, VerificationCode); if (!verfiyResult.Success) { return Json(new { isSuccess = false, message = verfiyResult.Message, code = 520, VerificationCode = verfiyResult.Entity, token }); }
服務端檢測到重復 ,返回520錯誤碼,同時包含驗證碼,要求客戶端下次請求附加此驗證碼,才能通過驗證
private Result<string> FilterDuplicateOrderSubmit(BillNew bill, string VerificationCode) {if (string.IsNullOrWhiteSpace(bill.Consignee) || string.IsNullOrWhiteSpace(bill.Shipper) || bill.EndDepartId == 0) { return new Result<string>("缺少必要校驗信息,不在校驗,讓業務規則校驗", true); } var lastOrderInfo = bill.Consignee + bill.ConsigneePhone + bill.Shipper + bill.ShipperPhone ;if (Session["LAST_ORDER_INFO"] != null && Session["LAST_ORDER_INFO"].ToString() == lastOrderInfo) { var code = RandomString.GetRndStrFor(3, false, false, true); if (Session["LAST_ORDER_INFO_VerificationCode"] == null) { Session["LAST_ORDER_INFO_VerificationCode"] = code; return new Result<string>("<font color=\"red\">本次提交信息與上次提交相似,可能造成重復,請務必核對確認。</font><br/>如確認無誤,請在頁面右下方輸入正確驗證碼后提交。", false, code); } else { if (Session["LAST_ORDER_INFO_VerificationCode"].ToString() != VerificationCode) { Session["LAST_ORDER_INFO_VerificationCode"] = code; return new Result<string>("輸入的驗證碼不正確,請在頁面右下方輸入正確驗證碼后提交。<br/><font color=\"red\">本次提交信息與上次提交相似,可能造成重復,請務必核對確認。</font>", false, code); } else { Session["LAST_ORDER_INFO"] = lastOrderInfo; Session["LAST_ORDER_INFO_VerificationCode"] = null; return new Result<string>("校驗通過", true); } } } Session["LAST_ORDER_INFO"] = lastOrderInfo; return new Result<string>("無重復!", true); }
