首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

ASP/VBScript 頁面重複提交導致數據庫雙重插入:PRG 模式與冪等性解決方案

     編輯:程式設計綜合問答

問題現象

經典 ASP (VBScript) 頁面 `zf.asp`:點擊鏈接跳轉執行插入邏輯,**每次點擊插入兩條相同記錄**;刷新頁面 (F5) 僅插入一條。

根因分析:瀏覽器預取/預渲染導致雙重請求

  • **鏈接預取** (``) 或 **瀏覽器預渲染** (Chrome 預渲染、Edge 預加載) 在用戶懸停/點擊前**靜默發起 GET 請求**執行插入邏輯。
  • 用戶實際點擊時,瀏覽器再次發起**正式導航請求**,再次執行插入 → **雙重插入**。
  • 刷新 (F5) 只發起一次導航請求 → 單次插入。

驗證方法

  1. 打開瀏覽器開發者工具 → **Network 面板** → 勾選 "Preserve log"。
  2. 點擊「轉發」鏈接,觀察 `zf.asp` 是否出現**兩次**請求 (其中一條可能標記 `prefetch` 或 `prerender`)。
  3. 檢查請求頭 `Purpose: prefetch` 或 `Sec-Purpose: prefetch`。

解決方案 (按推薦度排序)

方案原理實現難度適用性
PRG 模式 (Post-Redirect-Get) - 最佳鏈接改為 POST 表單提交 → 後端處理完**重定向 (302)** 到結果頁 → 瀏覽器不會預取 POST,刷新也不重複提交中 (需改鏈接為表單)所有 Web 應用通用最佳實踐
冪等性 Token (一次性令牌)生成唯一 Token 存 Session/DB → 頁面隱藏域帶上 → 處理前驗證 Token 有效性 → 標記已用/刪除 → 重複請求自動拒絕中無法改 POST 時的備選
檢查請求頭拒絕預取`If Request.ServerVariables("HTTP_SEC_PURPOSE") = "prefetch" Then Response.End`低依賴瀏覽器發送標準頭,非標準行為可能漏網
GET 改為 POST + JavaScript 提交鏈接點擊觸發 JS `form.submit()`,非直接導航低需 JS 啟用,預取通常不執行 JS
業務層去重 (唯一約束)DB 表加唯一索引 (`user_id`, `content`, `create_time` 組合) → 插入捕獲重複鍵錯誤忽略低治標不治本,但作為最後防線必須有

PRG 模式代碼示例 (ASP/VBScript)



">
<% ' 1. 驗證參數、權限 ' 2. 執行插入/更新業務邏輯 ' 3. 重定向回列表頁 (或結果頁) Response.Redirect "list.asp?msg=success" %>

最佳實踐總結

  1. **嚴禁 GET 請求執行寫操作** (INSERT/UPDATE/DELETE/發送郵件/支付)。**寫操作必須用 POST/PUT/DELETE**。
  2. **PRG 模式** 是解決「重複提交、刷新重複、瀏覽器預取」的**黃金標準**。
  3. **冪等性設計** (Token/業務唯一鍵) 是分布式系統、微服務、支付系統的**必修課**。
  4. **瀏覽器行為不可控**:預取、預渲染、後退緩存、雙擊、網絡重試,後端**必須假設請求會重複到達**並做好防重。

最佳回答核心:「打開浏覽器開發工具監測 轉發的這個頁面是否有別的請求操作。」—— 直接指向 Network 面板驗證雙重請求假設,排查思路清晰。

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