這篇是Unobtrusive Client Validation的續集。覺得Unobtrusive唸起來太繞舌,硬要直譯成"不唐突的; 不冒昧的; 謙虛的;不引人注目的"好像也沒有比較簡短有力,於是在"低調"跟"謙恭"兩個詞間猶豫了一下,最後捨通俗就氣質,決定將Unobtrusive翻成帶點文學味的"謙恭",也算配合本站技術文章常暴走突變成詩歌散文的獨特風格。(謎之聲: 有些人就是咬文嚼字成性沒錯啦! 但文章總是有錯字是怎麼回事?) PS: 斟酌了一下,擔心謙恭太過文縐縐,有人看不懂,決定改成"謙卑",或者有人覺得"謙恭"比較好?

這回介紹如何透過謙卑式寫法設定remote規則,也就是將欄位內容以HttpRequest方式送至ASP.NET Server端進行驗證的範例:

<%@ Page Language="C#" %>
 
<!DOCTYPE html>
 
<script runat="server">
    void Page_Load(object sender, EventArgs e)
    {
        if (Request.HttpMethod == "POST" && Request["mode"] == "check_member")
        {
            if (string.IsNullOrEmpty(Request["tExtra1"]) ||
                string.IsNullOrEmpty(Request["tExtra2"]))
                //檢核失敗傳回false會顯示data-val-remote指定的訊息
                Response.Write("false");
            else
            {
                string[] members = { "Jeffrey", "Darkthread", "SoundOfMystery" };
                string tRemote = Request["tRemote"];
                if (members.Contains(tRemote)) //檢核過關傳回true
                    Response.Write("true");
                else if (tRemote == "Shit") //檢核失敗可傳回指定訊息覆寫原錯誤訊息
                    Response.Write(@"""不要說髒話!"""); //傳回自訂訊息時需加雙引號
                else //tRemote非members裡的元素,檢核失敗傳回false
                    Response.Write("false");
            }
            Response.End();
        }
    }
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Unobstrusive JS Validation Demo</title>
   <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.js" 
     type="text/javascript"></script>   
    <script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.8.1/jquery.validate.js" 
     type="text/javascript"></script>   
    <script src="http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.js" 
     type="text/javascript"></script>  
    <style type="text/css">
body,input { font-size: 9pt; }     
.input-validation-error { border: 1px solid #ff0000 }
.input-validation-valid  { border: 1px solid #00ff00 }
.field-validation-error { color: #ff0000 }
.field-validation-valid { display: none }
.validation-summary-errors { font-weight: bold; color: #ff0000 }
.validation-summary-valid { display: none }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <input type="text" id="tExtra1" name="tExtra1" value="1" style="width:20px;" />
    <input type="text" id="tExtra2" name="tExtra2" value="2" style="width:20px;" />
    <input type="text" id="tRemote" name="tRemote" data-val="true" 
     data-val-required="不可空白" data-val-remote="查無會員編號或前兩欄空白" 
     data-val-remote-url="UnobJsVald.aspx?mode=check_member"
     data-val-remote-type="POST" data-val-remote-additionalfields="tExtra1,tExtra2"
     />
    <span data-valmsg-for="tRemote"></span>
    </div>
    <input type="submit" id="send" value="Send" />
    </form>
</body>
</html>

簡單介紹remote相關參數:

  • data-val-remote 為檢核失敗的訊息(Server端也可傳回訊息字串取代之)
  • data-val-remote-url 為檢核網頁程式的網址
  • data-val-remote-type 可為POST或GET(預設為GET),若不想傳送內容出現在URL,建議用POST
  • data-val-remote-additionalfields 要額外多傳的欄位名稱,可用","分隔指定多欄,若沒有就不用給

在Server端,用Request["fieldName"]可以承接前端傳來的欄位內容,檢核成功時Response.Write("true"),失敗則Response.Write("false"),若失敗時要另傳特定錯誤訊息,則可Response.Write("\"訊息內容\"")。 (因前端會用JSON解析傳回內容,故記得前後加上雙引號才會被轉型成字串。)

另外我又做了些研究: 將tExtra1, tExtra2移除,並將remote-type改為GET,使用IE9 Dev Tools觀察操作期間的HttpRequest發送行為:

注意到了嗎? 第一次送出ASP.NET進行檢核後,之後每輸入一個字元,在keyup事件時就會觸發送出一個Request! 剛開始我頗為驚慌,認為如此豈不將送出一堆多餘Request,形同對Server進行DOS攻擊? 但仔細探究jQuery.validation原始碼,才發現其中內含精巧Pending調節設計,在Server端還沒有回應前,會放棄該期間原本要發送的Request,並不會產生瘋狂連送灌爆Server的舉動。

為了驗證Pending機制的功效,在Server端做點修改,在Response.End()前加入一行System.Threading.Thread.Sleep(500);,延遲0.5秒才回應。此時HttpRequest發送狀況變成:

當送出tRemote=J,檢核需耗時0.5秒,其間輸入的e, f字元並沒有觸發Request,直到取得回應後再輸入f,才再送出tRemote=Jeff。由此觀之,jQuery.valdation能依Server端的回應效率調節送出Request的頻率。我認為這樣已經是十分優秀的設計,Server忙回應慢Request自然變少,不致壓垮Server;但若還是擔心它增加伺服器負載,則不妨在Server端用Thread.Sleep做調節,以一點延遲換取在大量使用者連線時降低負荷,應是簡單有效的改善方法。

PS: 這裡介紹的是非ASP.NET MVC 3環境下應用謙卑式客戶端檢核的做法,若為ASP.NET MVC3專案,已有內建的輔助機制,實做起來更簡單,細節可參考demo的介紹文章


Comments

# by Ike

「data-val-remote-additionfields」 應為 「data-val-remote-additionalfields」

# by Jeffrey

to lke, 謝,已校正。

Post a comment