注冊登錄過程點滴(三):解決MVC3中使用Ajax.BeginForm會重復提交數據的問題


MVC3這個開發框架還是很受大家歡迎的,我個人也非常喜歡,逢人總要誇獎一番,雖然還有很多地方需要完善,但總體上來說很棒!

不過,最近碰到一個比較糾結的問題,在點擊注冊時,為了使用一些友好的前端交互效果,所以使用 Ajax.BeginForm的方式,代碼如下:

@using (Ajax.BeginForm( " Register "" Account "new AjaxOptions { UpdateTargetId =  " ResultPannel ", OnBegin =  " RegOngoing ", OnSuccess =  " RegDone " }))
{...

分別通過 RegOngoing和 RegDone 執行注冊過程中和完成后的前端提示效果。

但這種方式經常會在數據庫中出現重復的數據,分析了一下原因,初步判斷應該是注冊事件被重復提交了,雖然在后端邏輯層會檢測數據是否存在,但其執行過程中本質上是會順序執行各種邏輯,所以在前一條還沒有插入數據庫,后一天已經被提交過來被檢測的概率是存在的,尤其是如果在數據訪問層端有較長的事務性邏輯存在的話,那這種重復提交的概率會更高!

 

采取的第一套方法:就是在用戶點擊后將注冊按鈕disable掉,並給與友好提示,避免用戶去重復點擊注冊...

function RegOngoing() {
   $( " #Register ").attr( " disabled "true);
   $( " #Register ").val( " 信息提交中... ");}

 這在很長一段時間內我們都認為解決了這個問題,可是在月黑分高的一個晚上,重復數據又出現了,這下糾結了,難道是被黑了?

利用一切可利用的資源,google、baidu、博客園、qq群等等到處找問題根源,都沒有很好的結果。最近團隊開會,仔細的分析了一下,發覺問題可能還是出在上面分析過的可能性,比如:很多用戶有雙擊的習慣,很多用戶有連續按回答的習慣...,只要RegOngoing反應遲鈍一點,就還是會存在這種被重復提交注冊的概率,雖然概率很小,但問題不能放過去,針對此種可能性,我們對這個注冊場景進行了無思考時間的壓力測試,發覺果真還是會被重復提交。

 

這樣,第二套方案應運而生: 采用token預防機制,在Register的action中增加一個基於IP的token策略,並在注冊邏輯執行完成后刪除token(這里不管是否成功,都必須刪除哦,不然你再想注冊就有可能不行)。


[HttpPost]

public ActionResult Register(RegisterModel reg)
        {
            //防止用戶並發提交數據
            string key = StringHelper.GetClientIP();
            if (!string.IsNullOrEmpty(RegTokenHelper.findTokenByKey(key)))
            {
                return Content("errorSubmit");
            }
            //生成用戶Token
            RegTokenHelper.generateToken(key);

            if (IsValidateCode(reg.sCode) == false)
            {
                //刪除Token
                RegTokenHelper.deleteToken(key);
                return Content("errorCode");
            }

            ...
                        
            //刪除Token
            RegTokenHelper.deleteToken(key);
            return Content(url);
        }

 這里主要是用本機的IP作為本機唯一訪問的標識,至於token值可以自己生成,也可以用系統的,我們采用的是guid值。

 

至此,這個問題基本上可以告一段落了!但是其實不知道大家發現沒有,上述方法中還存在一定的問題,或者注冊失敗的風險,就是當用戶在同一個局域網內並發的進行注冊,那是有可能失敗的,因為其token是相同的,后者會被認為是已經正在注冊!

這種場景其實也是有解決方法,就是不要使用IP作為key,而采用session。根據我們網站的用戶特點,前者發生的概率實在是微乎其微,而且本質上沒有什么危害性,所以我們沒有采用session,而默認接受這種風險了^_^

 至於大家要追求完美,那就無可非議了! 同時希望MVC的團隊能從框架性上去解決這個問題,因為這種場景是在是太多啦!!!

如果大牛們還有更好的辦法,Q我或者留言給我吧 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM