首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

使用 HttpModule 防止 Web 表單重複提交

     編輯:關於ASP.NET

問題情境

網路延遲或伺服器回應緩慢時,使用者可能重複點擊提交按鈕,導致資料重複寫入、伺服器負載飆升。傳統做法在按鈕點擊後用 JavaScript 禁用按鈕,但無法防止使用者重新整理(F5)或直接重送 POST 請求。

HttpModule 方案優勢

  • 全域攔截所有請求,無需修改個別頁面。
  • 伺服器端驗證,無法被繞過。
  • 可整合快取機制,自動過期釋放鎖定。
  • 支援自訂介面(如遮罩層)提升使用者體驗。

核心實作:NonReduplicatePostModule

public class NonReduplicatePostModule : IHttpModule
{
 private static readonly ILog log = LogManager.GetLogger(typeof(NonReduplicatePostModule));
 private const string HiddenFieldName = "__NonReduplicatePostModule__";
 private const string MaskDivScriptUrl = "~/js/maskDiv.js";
 private const string OnFormSubmitScript = "Evlon.MaskDiv.Instance.show();";

 public void Init(HttpApplication context)
 {
 context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
 }

 public void Dispose() { }

 private void OnPreRequestHandlerExecute(object sender, EventArgs e)
 {
 HttpApplication app = (HttpApplication)sender;
 Page page = app.Context.Handler as Page;
 if (page == null) return;

 page.PreRender += (s, args) =>
 {
 // 註冊客戶端遮罩腳本
 if (!page.ClientScript.IsClientScriptBlockRegistered("MaskDiv"))
 {
 page.ClientScript.RegisterClientScriptInclude("MaskDiv", page.ResolveUrl(MaskDivScriptUrl));
 }
 // 在表單提交時觸發遮罩
 HtmlForm form = page.Form;
 if (form != null) form.Attributes["onsubmit"] = OnFormSubmitScript;
 };

 // 檢查重複提交標記
 string flag = app.Request.Form[HiddenFieldName];
 if (!string.IsNullOrEmpty(flag))
 {
 if (app.Context.Cache[flag] != null)
 {
 log.Debug("Found reduplicate post");
 // 切換到重複提交處理器
 if (page is IReduplicatePostHandler)
 app.Context.Handler = new ReduplicatePostHandler((IReduplicatePostHandler)page);
 else
 app.Context.Handler = new ReduplicatePostHandler();
 }
 else
 {
 // 首次提交,存入快取 1 分鐘
 app.Context.Cache.Add(flag, DateTime.Now, null,
 Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1),
 CacheItemPriority.Normal, null);
 }
 }
 }
}

關鍵點解析

  1. 隱藏欄位標記:在表單中加入 ``,可由頁面自行產生(如 GUID)。
  2. 快取機制:使用 `HttpContext.Cache` 儲存提交標記,設定滑動過期 1 分鐘,超時自動釋放。
  3. 處理器切換:偵測到重複提交時,將 `Context.Handler` 替換為 `ReduplicatePostHandler`,由實作 `IReduplicatePostHandler` 的頁面自行決定顯示錯誤訊息、導向頁面或記錄日誌。
  4. 客戶端遮罩:透過 `onsubmit` 事件呼叫 JavaScript 顯示遮罩層,防止使用者重複點擊(但無法阻擋 F5)。

Web.config 註冊

<system.web>
 <httpModules>
 <add name="NonReduplicatePostModule" type="Tests.NonReduplicatePostModule, TestAssembly" />
 </httpModules>
</system.web>
<!-- IIS 7+ 整合模式 -->
<system.webServer>
 <modules>
 <add name="NonReduplicatePostModule" type="Tests.NonReduplicatePostModule, TestAssembly" />
 </modules>
</system.webServer>

擴充介面定義

public interface IReduplicatePostHandler
{
 void HandleReduplicatePost(HttpContext context);
}

public class ReduplicatePostHandler : IHttpHandler
{
 private readonly IReduplicatePostHandler _pageHandler;
 public ReduplicatePostHandler(IReduplicatePostHandler handler = null)
 { _pageHandler = handler; }

 public bool IsReusable => false;

 public void ProcessRequest(HttpContext context)
 {
 if (_pageHandler != null)
 _pageHandler.HandleReduplicatePost(context);
 else
 context.Response.Write("請勿重複提交表單,系統正在處理中...");
 }
}

總結

HttpModule 提供乾淨、可重用的重複提交防護方案,結合伺服器端快取驗證與客戶端 UI 遮罩,兼顧安全性與使用者體驗。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved