Asp.net

防止在 ASP.Net 中重新送出表單(不重定向到我自己)

  • May 31, 2019

我有一個帶有 Form 元素 ( <form runat="server">) 的母版頁、一個帶有 Button 元素 ( <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Sync" />) 的內容頁,以及一個包含該Button1_Click函式的 Code Behind 頁面。

使用者來到頁面並點擊按鈕。程式碼背後的程式碼執行(在伺服器上),它更新數據庫中的一些表。Code behind 程式碼所做的最後一件事是InnerHTML在內容頁面上設置 Span 元素的成功或失敗消息。

這一切都很好。問題是如果使用者刷新頁面,表單被重新送出並且瀏覽器詢問這是否真的是使用者想要的。如果使用者的回答是肯定的,則重新執行 Code Behind 程式碼並再次更新數據庫。如果使用者做出否定的回應,那麼什麼也不會發生。

重新執行程式碼背後的程式碼沒什麼大不了的。它不會傷害任何東西。但這並不是我想要的行為。

我知道我可以使用 Response.Redirect() 重定向回頁面,但是使用者永遠不會看到我的成功或失敗消息。我應該提到該消息實際上不僅僅是“成功”或“失敗”,否則我想我可以在重定向的查詢字元串中添加一些內容。

有沒有辦法從程式碼隱藏程式碼中重置表單元素,以便如果使用者刷新頁面,表單不會重新送出?

首頁面…

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="IntuitSync.SiteMaster" %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:ipp="">
   <head runat="server">
   </head>
   <body>
       <form runat="server">
           <div runat="server" id="mainContetntDiv">
               <asp:ContentPlaceHolder ID="MainContent" runat="server" />
           </div>
       </form>
   </body>
</html>

內容…

<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="~/Site.master" CodeBehind="SyncToCloud.aspx.cs" Inherits="IntuitSync.SyncToCloud" %>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
   <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Sync" />
   <span runat="server" id="SyncStatus"></span>
</asp:Content>

背後的程式碼…

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.Web;

namespace IntuitSync
{
   public partial class SyncToCloud : System.Web.UI.Page
   {
       protected void Page_Load(object sender, EventArgs e)
       {
           //
       }

       protected void Button1_Click(object sender, EventArgs e)
       {
           /*
               Do a bunch of stuff and put the results in syncResults which is a List.
           */
           SyncStatus.InnerHtml = string.Join("", syncResults.ToArray()); // I'd rather do this...
           //Response.Redirect(Request.Url.PathAndQuery, true);  // ...and not do this.
       }
   }
}

非常感謝任何和所有幫助。

問題是你正在做一個表單 POST,如果使用者隨後刷新頁面,它會做它應該做的事情:重新送出 POST。沒有其他辦法了。因此,您可以使用的選項如下:

  1. 重定向到確認頁面,以某種方式將操作結果傳遞給確認頁面(如果查詢字元串/cookie/等不可行,通常從某個數據儲存庫重新載入)。
  2. 重定向到同一頁面,但通過查詢字元串參數傳遞成功消息(或者愚蠢地將其儲存在 session/ViewState/what-have-you-silliness 中)。
  3. 不要發布,而是做一個表單,因為看起來您沒有發布任何值,只是啟動某種伺服器端處理。為此,只需將您的表單從文章更改為獲取,或者只是做一個連結。這裡的危險是您不應該在任何 get 操作中進行任何變革性/破壞性操作。

注意:確保清理所有使用者輸入(始終將使用者輸入視為邪惡)。

您可能對最後一個選項最滿意,但這完全取決於“做一堆東西並將結果放入 syncResults …”真正需要什麼。

更新(多年後)

雖然這應該是顯而易見的,但對某些使用者來說可能還不夠明顯:您永遠不應該通過直接顯示未經清理的“通過查詢字元串參數的成功消息”來向 XSS 攻擊敞開心扉。這些建議認為這很明顯,但回想起來,這方面應該是明確的。

引用自:https://stackoverflow.com/questions/14761382