防止按鈕重複送出之問題延伸-doPostBack、submit 對 IsPostBack 值的影響

  • 15067
  • 0
  • C#
  • 2009-06-29

當我要防止 User 重複按下按鈕後造成資料重複送出的問題,我通常會使用 GetPostBackEventReference 來產生 doPostBack script,但發現自行撰寫 submit() 將頁面轉至另一個頁面後,IsPostBack 的值會等於 true?

當我要防止 User 重複按下按鈕後造成資料重複送出的問題,我通常會使用下面這種方式:

在 Page_Load 執行下列敘述 (.cs): 

執行後產生的 aspx 頁面內容如下:


<input type="submit" name="Button1" value="Button"
   onclick="this.disabled=true;__doPostBack('Button1','');" id="Button1" />

如此就可避免重複按下按鈕的問題,而我有個應用情境是,當 User 按下確定按鈕後,程式會將一些資料透過 submit 的方式送到另一頁中(假設為page2.aspx),而我在 page2.aspx 判斷 IsPostBack 的值竟然是等於 true,這跟我原本的認知中,submit 到另一頁時,另一頁的 IsPostBack 就是等於 false 的觀念不同!!

後來研究了之後,原來是被 __doPostBack 影響到,因為我的程式每次都產生 __doPostBack script,再加上執行我自己的 submit script 後,會變成在目的頁判斷 IsPostBack 的值都會等於 true!

於是就很好奇為什麼存在 __dosPostBack 就會使 IsPostBack=true,當 __doPostBack 不存在時就會是 IsPostBack=false,我是呼叫 submit() 遞交資料,而 __doPostBack 中也是用submit() 來遞交資料,為什麼一個會是 IsPostBack=true,一個會是IsPostBack=false?這 2 者有什麼不一樣呢?

先來看我自行產生 submit 的程式碼:


<input type='hidden' name='name1' value='value1' />
<script>
var myForm = document.form1;
myForm.action='page2.aspx';
myForm.__VIEWSTATE.name = 'NOVIEWSTATE';
myForm.__VIEWSTATE.value = '';
myForm.submit();
</script>

這程式是將 name1 的值傳送到 page2.aspx 頁面,我指定了 action='page2.aspx',並將 ViewState 更名及清空內容,最後 submit() 送出。

再來看看 __doPostBack 的程式碼:


<input type='hidden' name='__EVENTTARGET' id='__EVENTTARGET' value='' />
<input type='hidden' name='__EVENTARGUMENT' id='__EVENTARGUMENT' value='' />
<script type='text/javascript'>
var theForm = document.forms['form1'];
if (!theForm) {
    theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
</script>

這段程式在 submit 時會一併將隱藏欄位 __EVENTTARGET 及 __EVENTARGUMENT 傳回 Server,而關鍵就在這邊,Server 會判斷只要有傳回 __EVENTTARGET,不管值為何,都會使 IsPostBack=true。

後來再測試,若是 submit 到同一頁面時,只要存在 __VIEWSTATE 或 __EVENTTARGET 都會使 IsPostBack=true,而 submit 到另一頁面時,就不能將原頁的 __VIEWSTATE 也帶過去,這樣就會造成「Viewstate MAC 的驗證失敗」的訊息,所以我的做法是在轉到另一頁前先將 __VIEWSTATE 名稱改掉後再轉頁。

於是最後的解法就是,當按下按鈕回到 Server 處理完時若不需自行撰寫 submit() 進行轉頁,就使用 GetPostBackEventReference 產生 __doPostBack script ,若按下按鈕後需要以 submit() 轉到下一頁,那麼就不產生 __doPostBack script,如此一來就不會產生 __EVENTTARGET ,也就不會一併帶到下一頁而使 IsPostBack 等於 true 了,這樣就可以快樂的使用 IsPostBack 來做判斷了。