<!--此特效來(lái)源來(lái)互聯(lián)網(wǎng),由 Yagebu.com 收集整理-->
<!--禁止表單多次提交-->
<h4>禁止表單多次提交,表單提交一次后提交鍵變灰色</h4>
<script>
function submitonce(theform){
//if IE 4+ or NS 6+
if (document.all||document.getElementById){
//screen thru every element in the form, and hunt down "submit" and "reset"
for (i=0;i<theform.length;i++){
var tempobj=theform.elements[i]
if(tempobj.type.toLowerCase()=="submit"||tempobj.type.toLowerCase()=="reset")
//disable em
tempobj.disabled=true
}
}
}
</script>
<form method="POST" onSubmit="submitonce(this)">
<input type=input name="asdf">
<input type=submit name="OK">
</form>
1. 利用 javascript :
1.1 document.form1.submit();后加
document.body.innerHtml = "<center> Waiting...</center>"; //當然這里的html代碼就由你發(fā)揮了,還可把這段寫(xiě)成函數,這樣維護就方便了!
這一處理,就讓用戶(hù)在等待提交時(shí)不會(huì )誤以為沒(méi)提交而重復按提交按鈕!
1.2 按鈕設置
<SCRIPT LANGUAGE="JavaScript">
function changesubmit()
{
document.aa.B1.disabled = "true";
}
</script>
……
<form method="POST" action="aa.jsp" name="aa" onSubmit="return changesubmit()">
…………
<input type="submit" value="答題完畢" name="B1">
<input type="reset" value="重做" name="B2">
</form>
我們?yōu)g覽很多論壇發(fā)表帖子時(shí),單擊“發(fā)表”按鈕,這個(gè)按鈕就會(huì )變成灰色,并且還有提示如“正在提交,請稍候...”等,這樣做一方面讓用戶(hù)看到效果,避免長(cháng)時(shí)間等待網(wǎng)頁(yè)的煩躁,另一方面又防止了重復提交。
在.NET中沒(méi)有類(lèi)似的功能,不過(guò)我們已經(jīng)知道他就是一個(gè)普通按鈕的基礎上多加了一個(gè)功能而以。在.NET中,我們可以巧妙利用類(lèi)的繼承來(lái)制作這種按鈕。
這里我是用C#語(yǔ)言作為范例,其他語(yǔ)言可以舉一反三得到應用,這里不再贅述。
我們需要自己寫(xiě)一個(gè)類(lèi),這個(gè)類(lèi)繼承自System.Web.UI.WebControl.Button:
我們知道要實(shí)現這種功能需要借助JS腳本,.NET的控件提供了一個(gè)Attributes屬性用來(lái)添加任何想要的客戶(hù)端屬性。我們需要在客戶(hù)端的onclick中寫(xiě)入:this.disabled=true,來(lái)達到使按鈕變灰,另外,再用一句:this.value="正在提交,請稍候...",來(lái)使的按鈕的文字改變。
把插入腳本這一動(dòng)作放在了控件加載的時(shí)候進(jìn)行。因此,我們重寫(xiě)OnLoad方法:
上面這句向客戶(hù)端屬性中onclick添加了這些語(yǔ)句。記得重寫(xiě)函數是不要忘記最后要調用基類(lèi)的OnLoad方法。
編譯,然后就可以在網(wǎng)頁(yè)上使用了。
你可以作為一個(gè)單獨的控件庫項目來(lái)寫(xiě)這個(gè)東西,然后從工具箱上添加上,把他們拖動(dòng)到網(wǎng)頁(yè)中,就可使用了。大家還可以擴充一些實(shí)用的功能。具體控件的編程美化等等細節此處不再贅述。
4. 防止重復提交 JAVA 解決
1、當用戶(hù)進(jìn)行的是Refresh/Reload/Back/Forward操作、以及先Back再Submit操作時(shí),僅僅是reloading先前的結果頁(yè)。
2、當用戶(hù)重復提交同一個(gè)任務(wù)操作時(shí),后臺服務(wù)接收并處理第一次提交的任務(wù),后面提交不起作用(不轉向也不提示)。
3、該功能具有公用性。
基本形成思路:
(1)、在basic filter中實(shí)現公用性
if(true){//問(wèn)題1:如何確定是否為重復提交
...
chain.doFilter(request,response);
}else{
//問(wèn)題2:如何實(shí)現不轉向、不提示也不顯示空白頁(yè)
}
(2)、網(wǎng)上資料概括
a、提交表單后按鈕變灰/隱藏提交按鈕
b、在js里設置全局變量,提交后修改該變量的值,依據變量的值判斷是否重復提交
var flag=true;
function checkForm(){
if (flag==false){
return;
}
flag=false;
document.form1.submit();
}
c、struts (webwork沒(méi)有找到這個(gè)資料)
//驗證事務(wù)控制令牌,<html:form >會(huì )自動(dòng)根據session中標識生成一個(gè)隱含input代表令牌,防止兩次提交
在action中:
//<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae">
if (!isTokenValid(request))
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("error.transaction.token"));
resetToken(request); //刪除session中的令牌
action有這樣的一個(gè)方法生成令牌華
protected String generateToken(HttpServletRequest request) {
HttpSession session = request.getSession();
try {
byte id[] = session.getId().getBytes();
byte now[] =
new Long(System.currentTimeMillis()).toString().getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(id);
md.update(now);
return (toHex(md.digest()));
} catch (IllegalStateException e) {
return (null);
} catch (NoSuchAlgorithmException e) {
return (null);
}
}
d、用戶(hù)使用瀏覽器時(shí),可以經(jīng)常使用向后的按鈕,因此就有可能重復提交一個(gè)他們已經(jīng)提交過(guò)的form,這樣就會(huì )帶來(lái)一個(gè)重復事務(wù)處理的問(wèn)題。同樣,一個(gè)用戶(hù)也可能在接收到一個(gè)確認的頁(yè)面之前按下停止的按鈕,接著(zhù)再次提交同一個(gè)form。對于這些情況,我們都想跟蹤并且禁止這些重復的提交,我們可以使用一個(gè)控制servlet來(lái)提供一個(gè)控制點(diǎn),以解決這個(gè)問(wèn)題。
同步記號(Synchronizer (or Dvu) Token)
這個(gè)策略是為了解決重復的form提交問(wèn)題。一個(gè)同步的記號被設置在一個(gè)用戶(hù)的Session中,并且包含在返回到客戶(hù)的每一個(gè)form中。當form被提交時(shí),form中的同步標記就和Session中的同步標記作對比。在form首次提交的時(shí)候,這兩個(gè)標記應該是一樣的。如果標記不一樣,那么該form就會(huì )禁止提交,一個(gè)錯誤就會(huì )返回給用戶(hù)。在用戶(hù)提交一個(gè)form時(shí),如果按下瀏覽器中的后退按鈕并嘗試重新提交同一個(gè)form時(shí),標記就會(huì )出現不匹配的現象。
另一方面,如果兩個(gè)標記值匹配,那么我們就可以確信整個(gè)流程是正確的。在這種情況下,
5. 如何防止用戶(hù)重復提交數據
簡(jiǎn)單的解決方案:
最簡(jiǎn)單的方式就是當用戶(hù)提交之后,在你的服務(wù)器端控件的代碼中使用Response.Redirect("selfPage")語(yǔ)句。但是大多的數包括我都不使用這種方法。
多次提交:
請注意:這篇文章并不是有關(guān)如何防止在一個(gè)頁(yè)面中多次提交。這篇文章是教你在提交了請求之后如何防止頁(yè)面進(jìn)行刷新。情況是這樣的,當用戶(hù)提交了按鈕之后,最終用戶(hù)就不能再點(diǎn)擊提交按鈕了。但是這樣最終用戶(hù)仍然可以通過(guò)點(diǎn)擊瀏覽器的刷新按鈕來(lái)提交數據。如果要防止多次提交你可以去 http://metabuilders.com/網(wǎng)上找一些資料,它那里有一個(gè)提交控件可以用。
常規的解決方案
習慣的解決方法是存儲Session的ID和當提交時(shí)ViewState中存儲的SessionID相比較來(lái)防止用戶(hù)刷新屏屏幕。前提你的程序中允許了自動(dòng)回發(fā),如果不是的話(huà),就得在hidden field存儲這個(gè)變量了。下面給出一個(gè)典型的例子。在Page_Load事件中你存儲了第一次提交時(shí)的SessionID和一個(gè)時(shí)間戳。
protected System.Web.UI.WebControls.Button SubmitButton;
protected System.Web.UI.WebControls.Label RefreshID;
private void Page_Load(object sender, System.EventArgs e)
{
if (RefreshID.Text.Length == 0)
{
RefreshID.Text = Session.SessionID+DateTime.Now.Ticks.ToString();
}
}
private void Button1_Click(object sender, System.EventArgs e)
{
string sesToken = (string) Session[FrameworkConst.SYNC_CONTROL_KEYWORD]; string pageToken = RefreshID.Text;
if (sesToken != null && sesToken != pageToken)
{
Response.Write("The Refresh was performed after submit.");
}
else
{
// do your processing here to avoid Refresh trap
Response.Write("The processing is done here. Disabling submit
button so that user can not perform multiple submit.");
Response.Write("But still user can peform Refresh on page.");
}
Session[FrameworkConst.SYNC_CONTROL_KEYWORD] = Session.SessionID+DateTime.Now.Ticks.ToString();
RefreshID.Text = sesToken;
SubmitButton.Enabled = false;
}
不同的解決方案:
幸運的事,asp.net提供了一些更簡(jiǎn)單的方法。上面的解決方案的缺點(diǎn)是我們要在控鈕的事件中自己決定一些邏輯問(wèn)題。設想一下,如果在你的解決方案中有成百個(gè)要提交的頁(yè)面,你就得寫(xiě)上許多個(gè)這樣的邏輯。自定義web控件和HTTP MOdules提供了相同的解決法。你可以將這個(gè)控件入在你需要控制的頁(yè)面上,它就可以起作用了。當然,并不是所有的情況都需要的,比如說(shuō)搜索頁(yè)面是允許用戶(hù)刷新的。但是,在頁(yè)面中有插入、更新、刪除數據庫的操作時(shí),控制刷新按鈕是絕對有必要的。
下面來(lái)看一下上面的方案是如何工作的。
第一步:需要在System.web節中注冊HTTP Module模塊。
<httpModules>
<add name="SyncHttpModule" type="EAD.Controller.SyncHttpModule, sync"/>
</httpModules>
第二步:要在控制頁(yè)的頁(yè)面內放入我們開(kāi)發(fā)好的控件。
工作原理:
它的工作原理和前面普通講的是差不多的。只是這里提供了一個(gè)通用的方法。這里提供了一種通用的方式。在我看來(lái),如果你有一些好的模式,將大大的加快你的開(kāi)發(fā)速度。
我們需要在第一次提交時(shí)在Session中存儲標記,并在請求時(shí)比較它們是否不同。通過(guò)HTTP handler,我們在Session中存儲標記。有這樣的一個(gè)事件PreRequestHandlerExecute 我們可以通過(guò)它找到Session,如果是其它事件的話(huà)Session是不存在的,比如BeginRequest 事件。在這個(gè)事件中比較兩者的值,如果不同則證明是Refresh事件。這時(shí)你可以添加自己的處理方法,我一般是將轉向一個(gè)頁(yè)面告訴用戶(hù)不能反復提交。
private void OnPreRequestHandlerExecute(object source, EventArgs e)
{
HttpContext context = ((HttpApplication) source).Context;
string _keyword = FrameworkConst.SYNC_CONTROL_KEYWORD;
string sesToken = (string) context.Session[_keyword];
string reqToken = context.Request.Params[_keyword];
//如果沒(méi)有提交過(guò),則保存Session和標記值
if(reqToken != FrameworkConst.BYPASS_SYNC_KEYWORD)
{
context.Session[_keyword] = context.Session.SessionID+DateTime.Now.Ticks.ToString();
}
if(reqToken != null && reqToken != sesToken)
{
string path=context.Request.ApplicationPath+
&"/Common/SyncControl.aspx?returnUrl="+
&context.Request.Url.AbsolutePath;
context.Server.Transfer(path);
}
}
聯(lián)系客服