Wednesday, June 03, 2009 - 文章

關於jQuery AJAX cache參數

網友DD04問到$.ajaxSetup({ cache: false })的用途,我寫了一個小範例說明:

<%@ Page Language="C#" %>
<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Request["m"] == "t" )
        {
            Response.ContentType = "text/plain";
            System.Threading.Thread.Sleep(2000);
            Response.Write("Time: " + DateTime.Now.ToString("HH:mm:ss.fff") + "\n");
            Response.Write("Method: " + Request.HttpMethod + "\n");
            Response.Write("QueryString: " + Request.Url.Query + "\n");
            Response.Write("PostData: ");
            foreach (string key in Request.Form.Keys)
                Response.Write("\n" + key + "->" + Request.Form[key]);
            Response.End();
        }
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>jQuery Ajax Cache Demo</title>
    <script src="../js/jquery-1.3.2.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function() {
            //$.ajaxSetup({ cache: false });
            $("#btnPostTest").click(function() {
                $.post("default.aspx", { m: "t" }, showResult);
            });
            $("#btnGetTest").click(function() {
                $.get("default.aspx", { m: "t" }, showResult);
            });
            function showResult(d) {
                alert(d);
            }
        });
    </script>
</head>
<body>
    <input type="button" id="btnPostTest" value="Post Test"/>
    <input type="button" id="btnGetTest" value="Get Test"/>
</body>
</html>

以上的程式碼可以存成default.aspx後實際跑來玩(記得要校正jquery.1.3.2.js的網址)。在網頁裡我做了兩顆按鈕,按下後會分別觸發$.get()及$.post(),而呼叫的對象就是default.aspx本身。在Page_Load()裡有段邏輯,當Request["m"] == "t"時不顯示網頁,而是將Request相關資訊Response.Write回去給Javascript端。為了突顯Cache效應,我特別放了一個Thread.Sleep(2000),也就是說,每次執行時,要停頓兩秒後才會得到結果。

首先你可以按兩次Post Test,每次應該都會在兩秒後得到結果。接著按兩次Get Test試試,第一次測試跟Post Test差不多,兩秒後得到結果(此時留意一下結果中的時間 Time: HH:mm:ss.fff),但第二次按鈕的結果很有趣,按下後不需等待兩秒,結果就立即彈出,而其中顯示的時間還跟第一次傳回的值完全相同。這證明了$.get()預設會啟用Cache功能,同樣的Request第二次不會真的送出,而是直接由Cache取回結果。

接著,我們將$.ajaxSetup()前方的//封印解除,再測試一次。這回不管按Get Test幾次,每次都要等兩秒才會得到結果,表示結果不是來自Cache,而是真的送至後端執行。由傳回結果,我們可以發現QueryString中被加了料:

Time: 12:38:59.985
Method: GET
QueryString: ?_=1243921137980&m=t
PostData:

當我們設定cache=false時,jQuery在我們每次發出Request時,會補上一個參數"_",而其內容是每次皆不同的亂數,這是Javascript端很常見的迴避Cache技巧。由於參數值不相同,每次Request都被視為不同,就能避開Cache裡的舊資料,強迫每次都將Request送至Server端執行。

呼叫$.ajax()時可以指定cache參數,在$.get()時則無從設起,因此範例中用$.ajaxSetup()設定全域適用的cache選項。

在實務上,用$.get()與後端溝通時要嚴防CSRF漏洞(補充說明),可以的話,最好改用$.post方式為之。

jQuery XML selector在IE6下不支援逗號

IE又來找碴了,這回闖禍的是IE6。

以下的程式(可使用Mini jQuery Lab測試) ,利用jQuery selector去查詢XML中的XmlElement,我有段類似的Code開發期間在IE7/8、FF、Chrome、Safari、Opera下都正常,直到今天交付User測試,User冷不防丟出魔法卷軸,召喚出IE6大魔獸登場,一鎚襲來,我可憐的小網頁就這麼倒地不起...

$.getScript("jquery.xmlext.js", function() {
    var xd = $.parseXml("<items><notebook /><pc /></items>");
    var x = $(xd);
    x.find("notebook,pc").text("Y");
    alert(x.xml());
});

x.find("notebook,pc")語法在IE6下會產生錯誤("Number expected" @ jquery-1.3.2.js 1529 列)。我發現如果拆成x.find("notebook")及x.find("pc")倒可以過關。

原本推測是IE6所附的MSXML物件版本較舊,所以我找到以下的程式碼測試:

 

alert(MSXMLversion());
function MSXMLversion()
{
    var msxv = ""
    
    if(window.ActiveXObject)
    {
        try {
            msxv += ( new ActiveXObject("Microsoft.XMLHTTP"))? "Microsoft.XMLHTTP":"";
            msxv += ( new ActiveXObject("Msxml2.XMLHTTP"))? " / Msxml2.XMLHTTP":"";
            msxv += ( new ActiveXObject("Msxml2.XMLHTTP.3.0"))? " / Msxml2.XMLHTTP.3.0":"";
            msxv += ( new ActiveXObject("Msxml2.XMLHTTP.4.0"))? " / Msxml2.XMLHTTP.4.0":"";
            msxv += ( new ActiveXObject("Msxml2.XMLHTTP.5.0"))? " / Msxml2.XMLHTTP.5.0":"";
        } catch (e) {
 
        }
    }
    return msxv
} 

出乎意料,問題IE6跟正常IE8得到的都是: Microsoft.XMLHTTP / Msxml2.XMLHTTP / Msxml2.XMLHTTP.3.0。

如果問題不在XML Document Object,那麼有可能出在jquery的Sizzle核心... 沒有氣力去挖出深層原因,再次含淚將二合一的selector拆成兩個避開問題。

今天雖然被IE惡搞了兩次,看到殺了人還一臉無辜的IE6,心中倒是浮現一個另類想法。

IE在這場瀏覽器大戰中,位於一種比較奇怪的處境: 大家在使用其他瀏覽器時,即便無人催促,好像自然而然就會升級使用最新版本;只有在談IE時,就是必須考量仍佔有一定比例的侏儸紀時代版本。(我保證有成千上萬的Developer想把IE6拖去埋了) 從某個角度來說,拿IE6跟其他瀏覽器的最新版相比,未盡公平。

我覺得這個現象源於IE是許多不熟電腦使用者的唯一選擇(換句話說,它在M型化社會的另一端),許多人或許搞不清楚Internet、Browser是什麼,但知道"要上網就按那個藍色小e就對了"。在此前題下,不會有動機去更換更新版、功能更強大的瀏覽器,可能就著Windows內附的IE版本用到電腦報廢為止(願上天保佑至少有做Windows Update)。但不可諱言,在Web Developer眼中機車得要命的IE6倒是讓許多對電腦、網路一竅不通的人擁有了最基本與Internet接軌的能力,說來也是功不可沒。用這個角度去看待IE6,倒有幾份像是夾在高樓林立都市中的一大片老眷村,破舊髒亂有礙觀瞻,街狹巷窄治安不佳,與四周的現化代建築格格不入,但它的存在不容被忽視,提供廣大平民基本生活需求也是不爭的事實。如果你的網站想真要服務普羅大眾,就不能忽略它背後所代表的聲音,就像選立委一樣得走訪其間爭取每一張選票,無法瀟灑地置於腦後(所以寫網頁才這麼累)。但是,就都市的長期發展而言,它絕對是應被優先整頓改造的議題,只是進展似非操之在我。

話是這麼說啦,我還是希望IE6早點消失~~~ (謎之聲: 那廢話這麼多做啥?)

[2009-06-03補充] 剛好看到重灌狂人的這篇統計,IE6仍然佔IE版本的45%以上,仍是瀏覽器一哥,看來離"消失"還有好長的路要走...

Posted 03 June 2009 12:18 AMJeffrey | 2 comment(s)
Filed under: ,

搜尋

Go

<June 2009>
SunMonTueWedThuFriSat
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication