一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

探求網(wǎng)頁同步提交、ajax和comet不為人知的秘密(中篇)

 Y赫爾 2015-03-14

  深入研究某項(xiàng)技術(shù),了解使用這些技術(shù)的細(xì)節(jié),其實(shí)最終目的都是為了完成一個(gè)選擇問題:當(dāng)我們要使用這些技術(shù)解決某個(gè)具體的問題時(shí)候我們到底該如何去選擇。如果碰到有兩種技術(shù)可以讓我們達(dá)到同樣的目的,我們就會(huì)不自然的去比較它們之間的差異,通過對(duì)這些差異的梳理,我們就能得出在使用它們時(shí)候我們到底該如何取舍。

  上篇里我講到XMLHttpRequest可以更加精確的控制http請(qǐng)求的報(bào)文頭,如是乎我就去尋找在同步提交里我是否能像XMLHttpRequest那樣的去控制http的頭部信息呢,最終我發(fā)現(xiàn)同步提交下我們可以在html的head里設(shè)置meta標(biāo)簽,使用http-equiv來設(shè)置http的頭部信息,不過meta的頭部信息其實(shí)是服務(wù)器給瀏覽器的響應(yīng)頭部信息,而不是請(qǐng)求頭部信息,下面是我們最常用,最能影響頁面展示的meta寫法,如下所示:

<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta http-equiv="expires" content="31 Dec 2099">

 

 

  這個(gè)頭部是告訴瀏覽器該頁面是一個(gè)html文檔,字符集是UTF-8,還告訴瀏覽器你要將這個(gè)頁面緩存在瀏覽器里,如果用戶不清理瀏覽器緩存,那么該頁面在2099年12月31號(hào)前都可以從緩存讀取,不需要在從服務(wù)器下載整個(gè)html文檔了。

  Expire是服務(wù)端指定瀏覽器的緩存行為,在web前端優(yōu)化里它所代表的緩存能力是非常重要,ajax也能使用瀏覽器緩存,不過這塊知識(shí)需要和我后面要講的內(nèi)容相關(guān),所以這里先暫時(shí)擱置一下。

  Content-type在上篇文章里多次出現(xiàn),我們開發(fā)頁面時(shí)候,html的head里該屬性可謂是一個(gè)熟悉的陌生人,在很多用來開發(fā)頁面的IDE里,我們選擇模板創(chuàng)建一個(gè)頁面,這個(gè)標(biāo)簽都是默認(rèn)帶有的,都不用我們自己添加它,但是我在多年開發(fā)經(jīng)驗(yàn)我還真的碰到過content-type使用不當(dāng)所帶來的技術(shù)問題。

  很早前有位朋友請(qǐng)教我一個(gè)這樣的問題,他們公司有個(gè)web應(yīng)用,這個(gè)web應(yīng)用沒有太多的頁面,大部分是后臺(tái)程序,該系統(tǒng)的目的是對(duì)他們公司用戶提供一些特別的服務(wù),用戶如果要使用該服務(wù)只需要在自己網(wǎng)站頁面里跨域請(qǐng)求他們系統(tǒng)提供的網(wǎng)頁,為了保證系統(tǒng)的安全,這位朋友的系統(tǒng)會(huì)對(duì)用戶發(fā)送的請(qǐng)求做很多安全性的檢查,這個(gè)檢查比較耗時(shí),但是又非常重要,因此他們?yōu)榱私o終端使用者以友好的用戶體驗(yàn),就在安全檢查正在處理時(shí)提供一個(gè)等待頁面,也許是因?yàn)檫@個(gè)朋友開發(fā)的系統(tǒng)服務(wù)端過重而且頁面太少太簡(jiǎn)單,不是特別擅長(zhǎng)頁面開發(fā)的他們開發(fā)時(shí)候就沒有單獨(dú)寫個(gè)等待頁面,而是將等待頁面放在后臺(tái)的servlet里直接構(gòu)造(其實(shí)就是在后臺(tái)直接拼寫頁面的字符串了),但是他們構(gòu)造時(shí)候忘了在這個(gè)簡(jiǎn)單頁面里加上content-type屬性,可惡的是這位朋友的系統(tǒng)測(cè)試時(shí)候沒有發(fā)現(xiàn)任何問題,可怕的是上了生產(chǎn)環(huán)境后某些調(diào)用他們系統(tǒng)的用戶在ie瀏覽器下頁面直接顯示了是源代碼而不是頁面,在非ie瀏覽器下卻是正常。不是所有人有問題,有問題也是部分瀏覽器,在自己的測(cè)試環(huán)境又模擬不出問題,這怎么搞,那位朋友的項(xiàng)目組花了兩天都沒弄明白怎么回事,而這時(shí)用戶的投訴是越來越多,如是他問我碰到過這種情況嗎?當(dāng)時(shí)我用ie和非ie抓包工具對(duì)比了在不同瀏覽器里http請(qǐng)求的請(qǐng)求頭和響應(yīng)頭,發(fā)現(xiàn)了區(qū)別:有的瀏覽器content-type是text/html,有的是text/plain,ie瀏覽器下都是text/plain,非ie兩種皆有,不過ie下如果是text/plain,那么頁面就會(huì)顯示源碼,如是我把我看到的現(xiàn)象告訴了這位朋友,這位朋友查閱下代碼發(fā)現(xiàn)他們構(gòu)造等待頁面時(shí)候沒有指定content-type頭,如是他們強(qiáng)制指定該頭為text/html,問題就解決。雖然問題解決了,但是我們還是沒有找到什么地方出問題了,為什么測(cè)試環(huán)境下不能重現(xiàn)問題的發(fā)生,這個(gè)現(xiàn)象對(duì)于做過互聯(lián)網(wǎng)開發(fā)的朋友可能就很好理解了,互聯(lián)網(wǎng)的應(yīng)用部署的網(wǎng)絡(luò)環(huán)境是非常復(fù)雜的,用戶從瀏覽器發(fā)送一個(gè)http請(qǐng)求到服務(wù)端,這個(gè)過程并不是像我們平時(shí)開發(fā)那樣直接到像tomcat,Jboss這些web容器,而是會(huì)經(jīng)過好多路徑,最常見的有cdn,負(fù)載均衡設(shè)備,靜態(tài)資源服務(wù)器例如apache等等,請(qǐng)求通過的這些環(huán)節(jié)都有權(quán)限和能力更改http報(bào)文,如果你們的網(wǎng)站規(guī)模越大,那么網(wǎng)絡(luò)環(huán)境會(huì)更加復(fù)雜,幾乎很難找到一個(gè)知道這所有細(xì)節(jié)的人,所以在互聯(lián)網(wǎng)公司都會(huì)有一個(gè)預(yù)發(fā)布環(huán)境,這個(gè)環(huán)境會(huì)盡最大努力模擬真實(shí)環(huán)境,雖然這個(gè)環(huán)境也是為了測(cè)試,但很多公司的預(yù)發(fā)布環(huán)境是可以在外網(wǎng)訪問,如果預(yù)發(fā)布環(huán)境設(shè)計(jì)的好,就能很有效的保證系統(tǒng)投產(chǎn)后的安全性,不過最有效能避免上面問題發(fā)生的手段還是自己技術(shù)、經(jīng)驗(yàn)要過硬。

  Content-type很有用,多理解下它可以為我們解決更多疑惑,詳細(xì)講解這個(gè)屬性不是本文的主題,下面我給感興趣的朋友兩個(gè)鏈接,有興趣可以瞧瞧:

http://baike.baidu.com/view/1547292.htm?fr=aladdin

http://tool.oschina.net/commons

  大多數(shù)時(shí)候,在同步請(qǐng)求里我們發(fā)送http請(qǐng)求給服務(wù)端是不需要了解太多content-type的作用,其實(shí)很多http頭也不用過多關(guān)心,但是有個(gè)東西特別是像我們這種使用漢字而非英語的國(guó)家,對(duì)字符集的編碼還是要倍加注意的。

  雖然html頭部設(shè)置charset的編碼是UTF-8,這是響應(yīng)頭的字符集,但是如果我們以這個(gè)響應(yīng)的頁面接著做http請(qǐng)求,那么這個(gè)編碼級(jí)會(huì)影響到提交請(qǐng)求的字符編碼即我們?nèi)绻蛔鎏貏e指定那么之后在這個(gè)頁面所有請(qǐng)求都是按照該編碼級(jí)進(jìn)行的。那么問題來了,如果我們想從一個(gè)UTF-8頁面請(qǐng)求一個(gè)后臺(tái)只能接收GBK編碼數(shù)據(jù)的接口時(shí)候,那么我們?cè)趺锤倪@個(gè)請(qǐng)求的編碼了,問題更進(jìn)一步點(diǎn),我們?cè)撊绾卧谕秸?qǐng)求里控制請(qǐng)求的http頭,至少是很重要的content-type屬性呢?

  同步提交核心是form,這和ajax的核心是XMLhttpRequest一樣,在form標(biāo)簽下有個(gè)屬性accept-charset,該屬性規(guī)定服務(wù)器處理表單數(shù)據(jù)所接受的字符集。accept-charset 屬性允許您指定一系列字符集,服務(wù)器必須支持這些字符集,從而得以正確解釋表單中的數(shù)據(jù)。

  該屬性的值是用引號(hào)包含字符集名稱列表。如果可接受字符集與用戶所使用的字符即不相匹配的話,瀏覽器可以選擇忽略表單或是將該表單區(qū)別對(duì)待。此屬性的默認(rèn)值是 "unknown",表示表單的字符集與包含表單的文檔的字符集相同。不過這個(gè)屬性在ie下效果并不好,甚至有時(shí)會(huì)無效,所以如果排除開發(fā)者將編碼寫錯(cuò)的原因,而是請(qǐng)求方和響應(yīng)方約定做這樣的轉(zhuǎn)化,對(duì)于字符集的轉(zhuǎn)化在服務(wù)端做是最好的。

         Form表單還有一個(gè)重要的屬性對(duì)http請(qǐng)求有很大的影響那就是enctype,它包含三個(gè)取值,如下所示:

描述

application/x-www-form-urlencoded

在發(fā)送前編碼所有字符(默認(rèn))

multipart/form-data

不對(duì)字符編碼。

在使用包含文件上傳控件的表單時(shí),必須使用該值。

text/plain

空格轉(zhuǎn)換為 "+" 加號(hào),但不對(duì)特殊字符編碼。

  第一行的值在我本文上篇里我曾提到過多次,現(xiàn)在我們知道它在瀏覽器里的作用了,form表單enctype默認(rèn)的屬性值,它讓瀏覽器在請(qǐng)求發(fā)送前編碼請(qǐng)求的數(shù)據(jù),為什么瀏覽器要編碼請(qǐng)求數(shù)據(jù)了?根本原因是因?yàn)殡娔X是美國(guó)人發(fā)明的,美國(guó)人使用英文字母給電腦輸入數(shù)據(jù),而像我們中國(guó)人則是使用方塊字漢字,而漢字對(duì)于電腦而言是一種特殊字符,不能使用幾個(gè)字母組合簡(jiǎn)單表示的,放眼全球,這種問題不僅僅發(fā)生在漢字上,韓文,日本等等非字母的語言都會(huì)存在同樣問題,但是網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)都是二進(jìn)制,為了讓請(qǐng)求數(shù)據(jù)在服務(wù)端能被正確還原服務(wù)端就必須有一個(gè)能容納世界上所有語言的字符集例如UTF-8或則特有的字符集GBK規(guī)范進(jìn)行轉(zhuǎn)義,這就是application/x-www-form-urlencoded的作用,他告訴瀏覽器你要對(duì)請(qǐng)求數(shù)據(jù)轉(zhuǎn)碼。Form表單還能傳輸文件,文件是需要特別的解析器來解析,例如圖片要圖片解析器,word文檔要office解析,但是這些文件本身存儲(chǔ)就是二進(jìn)制,而且是特有的二進(jìn)制,因此網(wǎng)絡(luò)傳輸時(shí)候最好能保持原樣,如是乎有了multipart/form-data屬性,有時(shí)我們不想轉(zhuǎn)碼了那么就可以使用text/plain,這些參數(shù)最后都會(huì)體現(xiàn)在http請(qǐng)求頭部的content-type屬性里。

      由此可見form表單并不那么簡(jiǎn)單,它也幫我們開發(fā)屏蔽了許多技術(shù)細(xì)節(jié),所以當(dāng)我們不使用form表單提交同步請(qǐng)求時(shí)候就有可能掉進(jìn)這些細(xì)節(jié)陷阱里,最常見的一個(gè)問題就是使用非form提交的get請(qǐng)求,該get請(qǐng)求會(huì)傳參至服務(wù)端,而這個(gè)參數(shù)里包含中文例如:websit=博客園,如果我們直接這么寫,瀏覽器不會(huì)給我報(bào)錯(cuò),但是到了服務(wù)端后我們會(huì)發(fā)現(xiàn)參數(shù)變成亂碼,url造成的亂碼是讓很多初學(xué)者頭疼的問題,不過javascript早就預(yù)料到了,如是它提供了三對(duì)可以對(duì)字符串編碼的函數(shù),分別是: escape,encodeURI,encodeURIComponent,相應(yīng)3個(gè)解碼函數(shù):unescape,decodeURI,decodeURIComponent 。這個(gè)問題的根本就是我們提交請(qǐng)求失去了form的保護(hù),我們必須手動(dòng)指定form里enctype所提供的功能。關(guān)于上面三對(duì)函數(shù),本文不做過多講述,想了解的朋友可以問問度娘了。

      上面內(nèi)容是我講同步請(qǐng)求時(shí)候講掉的內(nèi)容,這里補(bǔ)上了,由上面的內(nèi)容我們可以看出同步提交對(duì)http頭部的控制能力是很差的。

       XMLHttprequest對(duì)http頭有著強(qiáng)大的控制能力,它可以通過setRequestHeader(名,值)來設(shè)置http的請(qǐng)求頭,方法getResponseHeader(名)獲取指定的頭,方法getReponseHeaders()獲取所有響應(yīng)頭信息,雖然http請(qǐng)求頭對(duì)于用戶是不可見的(用戶只關(guān)心http請(qǐng)求體的內(nèi)容,因?yàn)檎?qǐng)求才是用戶需要的),但是對(duì)于開發(fā)者而言http請(qǐng)求頭非常重要,因?yàn)閔ttp請(qǐng)求頭是整個(gè)http的領(lǐng)導(dǎo)者,我們可以通過控制http請(qǐng)求頭信息達(dá)到很多傳統(tǒng)http請(qǐng)求所不能達(dá)到的目的。

       在使用XMLHttpRequest時(shí)候如果我們不對(duì)請(qǐng)求頭做任何修改,默認(rèn)情況下瀏覽器會(huì)發(fā)送以下http頭部信息給服務(wù)器,它們分別是:

復(fù)制代碼
Accept:瀏覽器能夠處理的內(nèi)容類型;
Accpet-Charset:瀏覽器能夠顯示字符集;
Accept-Encoding:瀏覽器能夠處理的壓縮編碼;
Accept-Language:瀏覽器當(dāng)前設(shè)置的語言;
Connection:瀏覽器和服務(wù)器之間連接類型;
Cookie:當(dāng)前頁面設(shè)置的任何Cookie;
Host:發(fā)出請(qǐng)求頁面所在的域;
Referer:發(fā)出請(qǐng)求的頁面的url,
User-Agent:瀏覽器的用戶代理字符串。
復(fù)制代碼

 

  上面九個(gè)頭部信息是所有瀏覽器都會(huì)傳送的,不過瀏覽器類型不同,頭部信息可能還會(huì)有點(diǎn)差異。

  雖然setRequestHeader方法可以修改http頭部信息,但是如果我們修改上面9個(gè)屬性中的某些屬性會(huì)發(fā)現(xiàn)這種修改有時(shí)不頂用,這是某些瀏覽器出于安全考慮不讓開發(fā)者輕易更改,好在setRequestHeader方法還能自定義請(qǐng)求頭,如果我們想做一些與請(qǐng)求頭相關(guān)的特別處理,最好是自己定義請(qǐng)求頭。此外setRequestHeader方法使用要在open方法后,send方法前,否則會(huì)達(dá)不到效果。

         接下來是ajax技術(shù)里另外一個(gè)重點(diǎn)了:回調(diào)函數(shù)的使用。這里有一句話:ajax的回調(diào)函數(shù)是用來處理http請(qǐng)求響應(yīng)的,也就是說服務(wù)端給了瀏覽器請(qǐng)求結(jié)果才會(huì)調(diào)用ajax的回調(diào)函數(shù),這個(gè)說法對(duì)嗎?我覺得很多人都會(huì)認(rèn)為這句話是正確的,這里我先不告訴大家答案,先講講關(guān)于ajax回調(diào)函數(shù)的使用,大家請(qǐng)看下面的代碼:

復(fù)制代碼
xmlhttp.onreadystatechange=state_Change;

function state_Change()

{

if (xmlhttp.readyState==4)

  {// 4 = "loaded"

  if (xmlhttp.status==200)

    {// 200 = OK

    // ...our code here...

    }

  else

    {

    alert("Problem retrieving XML data");

    }

  }

}
復(fù)制代碼

  

  XMLHttpRequest的onreadystatechange方法用來接收回調(diào)函數(shù),回調(diào)函數(shù)里我們要判斷readyState的取值為4,status的取值為200時(shí)候,我們就認(rèn)為得到了成功的響應(yīng),否則就是沒有得到成功的響應(yīng)。我曾經(jīng)做過一個(gè)嘗試,就是去掉xmlhttp.readyState==4代碼,我發(fā)現(xiàn)else里的alert會(huì)執(zhí)行多次,點(diǎn)完了這些對(duì)話框后請(qǐng)求任然可以正確處理,這說明了一個(gè)問題:onreadystatechange方法是和readystate值有關(guān)的,每當(dāng)readystate值發(fā)生改變的時(shí)候onreadystatechange就會(huì)被執(zhí)行,其實(shí)從onreadystatechange的名字就能知道這點(diǎn)。

  XMLHttpRequest里readystate的取值如下所示:

復(fù)制代碼
    取值0:未初始化即還沒調(diào)用open方法;

    取值1:?jiǎn)?dòng)即已經(jīng)調(diào)用了open方法,但還沒有調(diào)用send方法;

    取值2:發(fā)送即調(diào)用send方法,但還沒有收到響應(yīng);

    取值3:接收即已經(jīng)接收到部分響應(yīng)數(shù)據(jù);

    取值4:完成即接收到了全部響應(yīng)數(shù)據(jù)。
復(fù)制代碼

 

  由此可見ajax的回調(diào)函數(shù)并不是只有當(dāng)獲得響應(yīng)時(shí)候才會(huì)觸發(fā),一個(gè)ajax請(qǐng)求用于記錄回調(diào)函數(shù)的onreadystatechange方法會(huì)被調(diào)用5遍,所以我們必須使用readystate==4來表明響應(yīng)成功。此外從readystate狀態(tài)值我們也可以發(fā)現(xiàn)onreadystatechange屬性的賦值要放在open方法之前,否則你的寫法是存在隱患的。

  了解了這個(gè)后,我們看看jQuery的ajax方法的使用,jQuery的ajax方法是對(duì)瀏覽器底層ajax操作的封裝,該方法屏蔽了瀏覽器實(shí)現(xiàn)之間的差異,同時(shí)還提供了一些方法,這些方法是對(duì)底層ajax操作的上層封裝,他能讓那些沒有深入理解原始ajax原理的人以方便,這里我們著重看下jQuery里ajax里回調(diào)函數(shù)的使用,下面是我摘抄jQuery文檔里的內(nèi)容:

復(fù)制代碼
如果要處理$.ajax()得到的數(shù)據(jù),則需要使用回調(diào)函數(shù)。beforeSend、error、dataFilter、success、complete。

beforeSend 在發(fā)送請(qǐng)求之前調(diào)用,并且傳入一個(gè)XMLHttpRequest作為參數(shù)。

error 在請(qǐng)求出錯(cuò)時(shí)調(diào)用。傳入XMLHttpRequest對(duì)象,描述錯(cuò)誤類型的字符串以及一個(gè)異常對(duì)象(如果有的話)

dataFilter 在請(qǐng)求成功之后調(diào)用。傳入返回的數(shù)據(jù)以及"dataType"參數(shù)的值。并且必須返回新的數(shù)據(jù)(可能是處理過的)傳遞給success回調(diào)函數(shù)。

success 當(dāng)請(qǐng)求之后調(diào)用。傳入返回后的數(shù)據(jù),以及包含成功代碼的字符串。

complete 當(dāng)請(qǐng)求完成之后調(diào)用這個(gè)函數(shù),無論成功或失敗。傳入XMLHttpRequest對(duì)象,以及一個(gè)包含成功或錯(cuò)誤代碼的字符串。
復(fù)制代碼

 

 

  上面的success方法就是readystate值為4,status的值為200的情形了(實(shí)際情況下status值會(huì)更多點(diǎn),后面再聊這個(gè)問題),complete是當(dāng)請(qǐng)求完成后調(diào)用的函數(shù),這個(gè)方法其實(shí)和status值無關(guān)了,只和readystate值為4有關(guān),beforeSend則是readystate狀態(tài)為1時(shí)候使用的,error方法就比較復(fù)雜點(diǎn)了,它是一個(gè)綜合錯(cuò)誤的考慮,反正就是不成功就成error了,dataFilter是根據(jù)用戶定義的響應(yīng)數(shù)據(jù)的類型(dataType)對(duì)返回?cái)?shù)據(jù)做相應(yīng)的轉(zhuǎn)化,一般我們很少使用該函數(shù),都是依賴jQuery內(nèi)部完成,不過這個(gè)回調(diào)是在success方法之前執(zhí)行。

  dataFilter回調(diào)函數(shù)可以對(duì)響應(yīng)數(shù)據(jù)進(jìn)行處理,這里就引出了一個(gè)新問題,我們通過XMLHttpRequest獲取的響應(yīng)數(shù)據(jù)有哪些類型,XMLHttpRequest有兩個(gè)屬性用來存儲(chǔ)響應(yīng)數(shù)據(jù),一個(gè)是responseText:文本類型的響應(yīng)數(shù)據(jù),其實(shí)就是字符串,responseXML:XML文檔類型的響應(yīng)數(shù)據(jù),該屬性只有在http的響應(yīng)頭是text/xml或者application/xml時(shí)候?yàn)g覽器會(huì)幫我們轉(zhuǎn)化,如果不是上述類型,該屬性則為null。

  我們使用jQuery的ajax方法時(shí)候,通過設(shè)定dataType屬性,我們會(huì)獲得更加豐富的響應(yīng)數(shù)據(jù),下面是我摘抄的jQuery文檔的內(nèi)容,如下所示:

復(fù)制代碼
dataType:預(yù)期服務(wù)器返回的數(shù)據(jù)類型。如果不指定,jQuery 將自動(dòng)根據(jù) HTTP 包 MIME 信息來智能判斷,比如XML MIME類型就被識(shí)別為XML。在1.4中,JSON就會(huì)生成一個(gè)JavaScript對(duì)象,而script則會(huì)執(zhí)行這個(gè)腳本。隨后服務(wù)器端返回的數(shù)據(jù)會(huì)根據(jù)這個(gè)值解析后,傳遞給回調(diào)函數(shù)??捎弥?

"xml": 返回 XML 文檔,可用 jQuery 處理。

"html": 返回純文本 HTML 信息;包含的script標(biāo)簽會(huì)在插入dom時(shí)執(zhí)行。

"script": 返回純文本 JavaScript 代碼。不會(huì)自動(dòng)緩存結(jié)果。除非設(shè)置了"cache"參數(shù)。'''注意:'''在遠(yuǎn)程請(qǐng)求時(shí)(不在同一個(gè)域下),所有POST請(qǐng)求都將轉(zhuǎn)為GET請(qǐng)求。(因?yàn)閷⑹褂肈OM的script標(biāo)簽來加載)

"json": 返回 JSON 數(shù)據(jù) 。

"jsonp": JSONP 格式。使用 JSONP 形式調(diào)用函數(shù)時(shí),如 "myurl?callback=?" jQuery 將自動(dòng)替換 ? 為正確的函數(shù)名,以執(zhí)行回調(diào)函數(shù)。

"text": 返回純文本字符串
復(fù)制代碼

  

  上面的大部分操作是jQuery幫我們完成的,如果我們定義了dataFilter回調(diào)函數(shù),該函數(shù)是在類型轉(zhuǎn)化前執(zhí)行的,就是說dataFilter操作的數(shù)據(jù)是ajax返回的原始數(shù)據(jù)。

  當(dāng)readystate值為3時(shí)候,我們會(huì)做到一些意想不到的功能,readystate為3的狀態(tài)很特別,這個(gè)時(shí)候服務(wù)器已經(jīng)給出了響應(yīng),但是響應(yīng)數(shù)據(jù)并沒有全部發(fā)送給瀏覽器,不過此時(shí)你操作responseText會(huì)發(fā)現(xiàn)里面是有數(shù)據(jù)的,但是這個(gè)數(shù)據(jù)不全,我曾見過使用XMLHttpRequest這個(gè)屬性有人做出了兩個(gè)效果,具體如下所述:

  效果一:雖然我們開發(fā)時(shí)候都是盡全力讓請(qǐng)求和響應(yīng)時(shí)間變得更短,但是某些請(qǐng)求處理是快不起來的例如:上傳文件或者瀏覽器接收超大的數(shù)據(jù),如果場(chǎng)景是后者即用戶請(qǐng)求數(shù)據(jù)量很小,但是接收數(shù)據(jù)很大,接收時(shí)間很長(zhǎng)的時(shí)候,我們一般都會(huì)做一個(gè)等待請(qǐng)求處理的效果,如果這個(gè)效果能有精確的進(jìn)度條,那么給用戶的體驗(yàn)是非常好的,http響應(yīng)報(bào)文頭里有個(gè)屬性就是content-length,這個(gè)屬性告訴瀏覽器整個(gè)響應(yīng)的大小,一般瀏覽器收到響應(yīng),就算這個(gè)響應(yīng)還只有部分?jǐn)?shù)據(jù),這個(gè)響應(yīng)頭也會(huì)先發(fā)送,之所以提前,是讓服務(wù)器知道數(shù)據(jù)接收到多少就表明接收完畢,所以在readystate為3時(shí)候我們可以通過計(jì)算收到響應(yīng)的大小和content-length做比較就能知道響應(yīng)接收到了那個(gè)階段了,這樣進(jìn)度條的進(jìn)度就會(huì)很精確。

  效果二:這個(gè)效果是我很多年前無意中看見一個(gè)國(guó)外網(wǎng)站發(fā)現(xiàn)的,可惜我現(xiàn)在不記得網(wǎng)址了,網(wǎng)頁的作者也是研究ajax的特點(diǎn)的,他通過ajax請(qǐng)求了一篇文章,然后這個(gè)文章會(huì)在頁面一行行的顯示出來,因?yàn)檫@個(gè)效果使用setTimeout函數(shù)在瀏覽器也能做,所以這位作者就控制服務(wù)端數(shù)據(jù)返回時(shí)間,瀏覽器收到部分?jǐn)?shù)據(jù)后就馬上在頁面上顯示出來。

  不過上述操作有個(gè)特點(diǎn),就是開發(fā)者都會(huì)定義一個(gè)回調(diào)函數(shù),使用setTimeout函數(shù)輪詢這個(gè)回調(diào)函數(shù),setTimeout和回調(diào)函數(shù)使用是在onreadystatechange回調(diào)函數(shù)里面,而且接收數(shù)據(jù)的字符串要用公共變量存儲(chǔ),所以這個(gè)效果做起來還是有點(diǎn)難度的,原因就是readystate狀態(tài)為3時(shí)候回調(diào)函數(shù)只能調(diào)用一次。

  在jQuery的ajax方法里有一個(gè)屬性ifModified,文檔的解釋是:

(默認(rèn): false) 僅在服務(wù)器數(shù)據(jù)改變時(shí)獲取新數(shù)據(jù)。使用 HTTP 包 Last-Modified 頭信息判斷。在jQuery 1.4中,他也會(huì)檢查服務(wù)器指定的'etag'來確定數(shù)據(jù)沒有被修改過。

  

  這個(gè)參數(shù)說明ajax技術(shù)可以對(duì)http的緩存進(jìn)行操作,所以有些javascript的書里講解ajax時(shí)候表示請(qǐng)求成功會(huì)使用兩個(gè)響應(yīng)碼,一個(gè)就是常見的200,另一個(gè)是304,304的響應(yīng)碼表明該請(qǐng)求的響應(yīng)要從瀏覽器緩存里取,不需要服務(wù)器直接返回了。

  為了說清楚ajax操作緩存,那我們首先要知道瀏覽器的緩存機(jī)制,在web前端優(yōu)化使用瀏覽器緩存是一個(gè)很重要的法則,那么如何讓瀏覽器能緩存我們的響應(yīng)呢?一般有兩種方式:

  方式一:通過expires、cache-control來控制,前者是指定緩存到期的具體日期,后者是指定緩存多久后過期例如10年后過期,我們第一次請(qǐng)求某個(gè)資源成功響應(yīng)碼為200,這個(gè)時(shí)候響應(yīng)頭里會(huì)返回一個(gè)last-modified回來,如果該資源我們?cè)O(shè)定了緩存,那么第二次請(qǐng)求在請(qǐng)求頭里會(huì)發(fā)送if-Modified-Since屬性,該屬性的值就是第一次返回的last-modified,服務(wù)器接收后發(fā)現(xiàn)資源沒有改變,服務(wù)器就會(huì)返回304響應(yīng)碼回來,304響應(yīng)碼就是告訴瀏覽器響應(yīng)結(jié)果從瀏覽器緩存里取。

  方式二:使用etag,etag是另一種緩存失效機(jī)制,使用etag的服務(wù)器會(huì)給指定資源計(jì)算一個(gè)hash值(一般用md5算的),第一次請(qǐng)求時(shí)候服務(wù)器會(huì)將這個(gè)值返回給瀏覽器,第二次請(qǐng)求瀏覽器會(huì)將這個(gè)值發(fā)送給服務(wù)器,服務(wù)器通過計(jì)算資源的hash值和傳來的值作比較后,如果值相等那么就表明資源沒有更改,這時(shí)服務(wù)器也會(huì)給一個(gè)304的響應(yīng)碼給瀏覽器,讓瀏覽器在自己緩存里去找對(duì)應(yīng)的響應(yīng)。

  不管是那種方式,如果請(qǐng)求已經(jīng)被緩存,服務(wù)器都會(huì)返回304響應(yīng)碼,使用瀏覽器緩存不代表瀏覽器不發(fā)送請(qǐng)求,是否取瀏覽器緩存是服務(wù)器來指揮的,只不過304請(qǐng)求不會(huì)返回響應(yīng)體,只有響應(yīng)頭,而且請(qǐng)求方式是get,這個(gè)請(qǐng)求非常小,速度非???。

  同樣當(dāng)ajax收到了304響應(yīng)碼時(shí)候,ajax就會(huì)從瀏覽器緩存里取響應(yīng)結(jié)果,這個(gè)操作XMLHttpRequest會(huì)自己幫我們做掉。

  不過關(guān)于304的情況有一點(diǎn)一定要注意,能被瀏覽器緩存的請(qǐng)求只有g(shù)et請(qǐng)求即原始請(qǐng)求一定要是get請(qǐng)求,post請(qǐng)求時(shí)沒法被瀏覽器緩存的。

  XMLHttpRequest非常強(qiáng)大,我這里的強(qiáng)大是想說它除了可以做異步請(qǐng)求還能做同步請(qǐng)求,前面我講了onreadystatechange,講了readystate,其實(shí)這兩個(gè)東西應(yīng)該可以說專屬于異步請(qǐng)求,為什么呢?在以前的文章里我講到nodejs的作者選擇javascript語言原因是因?yàn)閖avascript的回調(diào)機(jī)制,因?yàn)橛谢卣{(diào)就可以讓單線程的javascript做出異步的效果,既然是同步提交,定義回調(diào)函數(shù)還有意義嗎?所以如果我們使用XMLHttpquest做同步請(qǐng)求,我們的代碼可以這么寫:

復(fù)制代碼
  xmlhttp.open("GET",url,false);

  xmlhttp.send(null);

  if (xmlhttp.status==200)

    {// 200 = OK

    // ...our code here...

    }

  else

    {

    alert("Problem retrieving XML data");

    }
復(fù)制代碼

  

  代碼會(huì)按順序執(zhí)行的,如果請(qǐng)求很慢,照樣阻塞頁面執(zhí)行。

  看到這里估計(jì)有人會(huì)有疑問的,ajax的同步提交有價(jià)值嗎?這還不如用form來做同步提交,這個(gè)要具體問題具體看了,我在前面講到傳統(tǒng)的同步提交對(duì)http的精確控制能力很差,如果某些同步請(qǐng)求我們需要更多的http控制那么使用ajax比較好,此外傳統(tǒng)的同步請(qǐng)求響應(yīng)要么是覆蓋了原頁面,要么就是用個(gè)新窗體接收響應(yīng),但是同步的ajax對(duì)響應(yīng)的處理靈活度更大,相比之下ajax同步請(qǐng)求優(yōu)勢(shì)更大些。

  在jQuery的ajax里有一個(gè)屬性就是timeout,可以為ajax請(qǐng)求設(shè)置超時(shí)時(shí)間,在我前面講解ajax技術(shù)時(shí)候我們會(huì)發(fā)現(xiàn)XMLHttpRequest沒有一個(gè)屬性可以設(shè)置這個(gè)超時(shí)時(shí)間屬性,其實(shí)在ie8包括ie8以上的版本里,XMLHttpRequest擁有timeout屬性,其他瀏覽器沒有,但是XMLHttpRequest擁有一個(gè)abort方法,這個(gè)方法可以取消異步請(qǐng)求,記住是異步請(qǐng)求,同步操作這個(gè)方法無效,無效原因是同步提交下我們是沒機(jī)會(huì)執(zhí)行該方法的。有了這個(gè)方法我們就可以模擬ajax請(qǐng)求超時(shí)。

  哦,寫了8000多字了,看來本篇也無法寫完我這個(gè)主題,由此可見頁面的提交數(shù)據(jù)方式的學(xué)問是很大的。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    69老司机精品视频在线观看| 日韩高清毛片免费观看| 日韩和欧美的一区二区三区| 国产一区二区三区口爆在线| 国产色偷丝袜麻豆亚洲| 亚洲午夜福利不卡片在线| 久久99国产精品果冻传媒| 老司机精品一区二区三区| 国产成人在线一区二区三区| 亚洲欧洲一区二区综合精品| 少妇高潮呻吟浪语91| 国产一区二区三区不卡| 美女黄片大全在线观看| 国产欧美精品对白性色| 国产目拍亚洲精品区一区| 国产精品激情对白一区二区| 久久这里只精品免费福利| 国产一区麻豆水好多高潮| 欧美中文字幕日韩精品| 欧美日韩亚洲巨色人妻| 国产欧美日韩在线一区二区| 国产三级视频不卡在线观看| 国产一区二区三区丝袜不卡| 色老汉在线视频免费亚欧| 91超精品碰国产在线观看| 久久香蕉综合网精品视频| 五月的丁香婷婷综合网| 欧美丰满人妻少妇精品| 99久久免费中文字幕| 欧美丝袜诱惑一区二区| 国产又色又爽又黄又大| 久久99热成人网不卡| 精品人妻av区波多野结依| 国产亚洲中文日韩欧美综合网 | 欧美一区二区三区十区| 超薄丝袜足一区二区三区| 大香蕉再在线大香蕉再在线| 黄色美女日本的美女日人| 邻居人妻人公侵犯人妻视频| 国产日韩欧美一区二区| 欧美日韩亚洲精品内裤|