[筆記]《JavaScript進階程式設計》- Ajax與Comet

來源:互聯網
上載者:User

標籤:log   min   name   gre   正是   用法   錯誤   允許   而不是   

        在XHR出現之前,Ajax式的通訊必須藉助一些hack手段來實現,大多數是使用隱藏的架構或內嵌架構。

一、XMLHttpRequest 對象

1 XHR的用法

        在使用XHR對象時,要調用的第一個方法是open(),它接受3個參數:要發送的請求的類型(“get”、“post”等)、請求的URL和表示是否非同步發送請求的布爾值。

        要發送特定的請求,必須向下面這樣調用send()方法。send()方法要接受一個參數,作為請求主體發送的資料。如果不需要通過請求主題發送資料,則必須傳入null,因為這個參數對有些瀏覽器來說是必需的。

        當請求是同步時,JavaScript代碼會等到伺服器響應之後再繼續執行。在收到響應後,響應的資料會自動填滿XHR對象的屬性,相關的屬性簡介如下。

  • responseText:作為響應主體被返回的文本。
  • responseXML:如果響應的內容類型是“text/xml”或“application/xml”,這個屬性中將儲存包含著響應資料的XML DOM文檔。
  • status:響應的HTTP狀態。
  • statusText:狀態代碼的說明。

        在接受到響應後,第一步是檢查status屬性,以確定響應已經成功返回。一般來說,可以將HTTP狀態碼為200作為成功的標誌。此時,responseText屬性的內容已經就緒,而且在內容類型正確的情況下,responseXML也應該能夠訪問了。此時,狀態碼為304表示請求的資源並沒有被修改,可以直接使用瀏覽器中緩衝的版本;當然,也意味著響應是有效。

        XHR對象的readyState屬性,該屬性工作表示請求/響應過程的當前活動階段。這個屬性可取的值如下。

  • 0:未初始化。尚未調用open()方法。
  • 1:啟動。已經調用open()方法,但尚未調用send()方法。
  • 2:發送。已經調用send()方法,但尚未接收到響應。
  • 3:接受。已經接收到部分響應資料。
  • 4:完成。已經接收到全部響應資料,而且已經可以在用戶端使用了。

        只要readyState屬性的值由一個值變成另一個值,都會觸發一次readystatechange時間。可以利用這個事件來檢測每次狀態變化後readyState的值。

        在接受到響應之前還可以調用abort()方法來取消非同步請求,如下。

        xhr.abort();

        調用這個方法後,XHR對象會停止觸發事件,而且也不再允許訪問任何與響應有關的對象屬性。在終止請求之後,還應該對XHR對象進行解引用操作。由於記憶體原因,不建議從用XHR對象。

2 HTTP頭部資訊

        XHR對象也提供了操作要求標頭部和回應標頭部資訊的方法。

  • Accept:瀏覽器能夠處理的內容類型。
  • Accept-Charset:瀏覽器能夠顯示的字元集。
  • Accept-Encoding:瀏覽器能夠處理的壓縮編碼。
  • Accept-Language:瀏覽器當前設定的語言。
  • Connection:瀏覽器與伺服器之間串連的類型。
  • Cookie:當前版面設定的任何Cookie。
  • Host:發出請求的頁面所在的域。
  • Referer:發出請求的頁面的URI。
  • User-Agent:瀏覽器的使用者代理程式字串。

        使用setRequestHeader()方法可以設定自訂的要求標頭部資訊。這個方法接受兩個參數:頭部欄位的名稱和頭部欄位的值。要成功發送要求標頭部資訊,必須在調用open()方法之後切調用send()方法之前調用setRequestHeader()。

3 GET請求

        對XHR而言,位於傳入open()方法的URL末尾的查詢字串必須經過正確的編碼才行。查詢字串中每個參數的名稱和值都必須使用encodeURIComponet()進行編碼,然後才能放到URL末尾;而且所有名-值對兒都必須由和號(&)分隔。

4 POST請求

        使用XHR來模仿表單提交:首先將Content-Type頭部資訊設定為application/x-www-form-urlencoded,也就是表單提交時的內容類型,其次是以適當的格式建立一個字串。POST資料的格式與查詢字串相同。

二、XMLHttpRequest 2級

1 FormData

        FormData為序列化表單以及建立與表單格式相同的資料(用於通過XHR傳輸)。

        下面的代碼建立了一個FormData對象,並向其中添加了一些資料。

var data = new FormData();data.append("name", "Nicholas");

        append()方法接受兩個參數:鍵和值,分別對應表單欄位的名字和欄位中包含的值。可以如上這樣添加任意多個索引值對兒。而通過想FormData建構函式中傳入表單元素,也可以用表單元素的資料預先向其中填入索引值對兒:

var data = new FormData(document.forms[0]);

        建立了FormData的執行個體後,可以將它直接傳給XHR的send()方法。

        使用FormData的方便之處體現在不必明確地再XHR對象上佈建要求頭。XHR對象能夠識別傳入的資料類型是FormData的執行個體,並配置適當的頭部資訊。

2 逾時定義

        IE8為XHR對象添加了一個timeout屬性,表示請求再等待響應多少毫秒後就終止。在給timeout設定一個數值後,如果在規定的時間內瀏覽器還沒有接收到響應,那麼就會觸發timeout事件,進而會調用ontimeout事件處理常式。這項功能後來也被收入了XMLHttpRequest 2級規範中。

3 overrideMimeType()方法

        Firefox最早引入了overrideMimeType()方法,用於重寫XHR響應的MIME類型。這個方法也被納入了XMLHttpRequest 2級規範。因為返迴響應的MIME類型決定了XHR對下崗你如何處理它,所以提供了一種方法能夠重寫伺服器返回的MIME類型是很有用的。

三、進度事件

        PrograssEvents規範是W3C的一個工作草案,定義了與用戶端伺服器通訊有關的事件。這些事件最早其實只針對XHR操作,但目前也被其他API借鑒。有以下6個進度事件。

  • loadstart:在接收到響應資料的第一個位元組時觸發。
  • progress:在接受響應期間持續不斷地觸發。
  • error:在請求發生錯誤時觸發。
  • abort:在應為調用abort()方法而終止串連時觸發。
  • load:在接受到完整的響應資料時觸發。
  • loadend:在通訊完成或者觸發error、abort或load事件後觸發。

        每個請求都從觸發loadstart事件開始,接下來是一或多個progress事件,然後觸發error、abort或者load事件中的一個,最後以觸發loadend事件結束。

四、跨域資源共用

        通過XHR實現Ajax通訊的一個主要限制,來源於跨域安全性原則。

        CORS(Cross-Origin Resource Sharing,跨域安全資源共用)是W3C的一個工作草案,定義了在必須訪問跨域資源時,瀏覽器與伺服器應該如何溝通。CORS背後的基本思想,就是使用自訂的HTTP頭部讓瀏覽器與伺服器進行溝通,從而決定請求或響應時應該成功,還是應該失敗。

1 IE對CORS的實現

        微軟在IE8中引入了XDR(XDomainRequest)類型。這個對象與XHR類似,但能實現安全可靠的跨域通訊。

  • cookie不會隨請求發送,也不會隨響應返回。
  • 只能佈建要求頭部資訊中的Conent-Type欄位。
  • 不能訪問回應標頭部資訊。
  • 只支援GET和POST請求。

2 其他瀏覽器對CORS的實現

        WebKit通過XMLHttpRequest對象實現了對CORS的原生支援。要請求位於另一個域中的資源,使用標準的XHR對象並在open()方法中傳入絕對URL即可。

        跨域XHR對象也有一些限制。

  • 不能使用setRequestHeader()設定自訂頭部。
  • 不能發送和接受cookie。
  • 調用getAllResponseHeaders()方法總會返回Null 字元串。

五、其他跨域技術

1 映像Ping

        映像Ping是與伺服器進行簡單、單向的跨域通訊的一種方式。請求的資料是通過查詢字串形式發送的,而響應可以是任意內容,但通常是像素圖或204響應。通過映像Ping,瀏覽器得不到任何具體的資料,但通過偵聽load和error事件,它能知道響應是什麼時候接收到的。

var img = new Image();img.onload = img.onerror = function() {    alert(‘Done!‘);};img.src = ‘http://www.example.com/test?name=Nicholas‘;

        Ping的兩個主要的缺點,一是只能發送GET請求,二是無法訪問伺服器的響應文本。因此,映像Ping只能用於瀏覽器與伺服器間的單項通訊。

        映像Ping有兩個主要的缺點,一是只能發送GET請求,而是無法訪問伺服器的響應文本。

2 JSONP

        JSONP是JSON with padding(填充式JSON或參數式JSON)的簡寫。JSONP看起來與JSON差不多,只不過是包含在函數調用中的JSON,如下。

callback({"name": "Nicholas"});

        JSONP由兩部分組成:回呼函數和資料。回呼函數是當響應到來時應該在頁面中調用的函數。回呼函數的名字一般是在請求中指定的。而資料就是傳入回呼函數中的JSON資料。

        JSONP是通過動態<script>元素來使用的,使用時可以為src屬性指定一個跨域URL。因為JSONP是有效JavaScript代碼,所以在請求完成後,即在JSONP響應載入到頁面中以後,就會立即執行。

        與映像Ping相比,他的優點在於能夠直接存取響應文本,支援在瀏覽器與伺服器之間雙向通訊。不過,JSONP也有兩點不足。

        首先JSONP是從其他域中載入代碼執行。如果其他域不安全,很可能會在響應中夾帶一些惡意代碼,而此時除了完全放棄JSONP調用之外,沒有辦法追究。因此在使用不是你自己營運的Web服務時,一定要保證它安全可靠。

        其次,要確定JSONP請求是否失敗並不容易。雖然HTML5給<script>元素新增了一個onerror事件處理常式,但目前還沒有得到任何瀏覽器支援。為此,開發人員不得不使用計時器檢測指定時間內是否接收到了響應。但就算這樣也不能盡如人意,畢竟不是每個使用者上網的速度和頻寬都一樣。

3 Comet

        Comet是一種伺服器向頁面推送資料的技術。Comet能夠讓資訊近乎即時地推送到頁面上,非常適合處理體育比賽分數和股票報價。

        有兩種實現Comet的方式:長輪詢和流。長輪詢是傳統輪詢(也稱短輪詢)的一個翻版,即瀏覽器定時發送請求,看有沒有更新的資料。

        短輪詢是伺服器立即發送響應,無論資料是否有效,而長輪詢是等待發送響應。輪詢的優勢是所有瀏覽器都支援,因為使用XHR對象和setTimeout()就能實現。而你要做的就是決定什麼是否發送。

        第二種流行的Comet實現是HTTP流。流不同於上述兩種輪詢,因為它在頁面的整個生命週期內只使用一個HTTP串連。具體來說,就是瀏覽器向伺服器發送一個請求,而伺服器保持串連開啟,然後周期性地向瀏覽器發送資料。

        所有伺服器端語言都支援列印到輸出緩衝然後重新整理(將輸出緩衝中的內容一次性全部發送到用戶端)的功能。而這正是實現HTTP流的關鍵所在。

        通過偵聽readystatechange事件及檢測readyState的值是否為3,就可以利用XHR對象實現HTTP流。在上述這些瀏覽器中,隨著不斷從伺服器接收資料,readyState的值會周期性地變成3。當readyState值變為3時,responseText屬性中就會儲存接收到的所有資料。此時,就需要比較此前接收到的資料,決定從什麼位置開始取得最新的資料。使用XHR對象實現HTTP流的典型代碼如下所示。

function createStreamingCilent(url, progress, finished) {    var xhr = new XMLHttpRequest(),        received = 0;    xhr.open(‘get‘, url, true);    xhr.onreadystatechange = function() {        var result;        if(xhr.readyState == 3) {            result = xhr.responseText.substring(receivied);            received += result.length;            progress(result);        } else if(xhr.readyState == 4) {            finished(xhr.responseText);        }    };    xhr.send(null);    return xhr;}var client = createStreamingClient(‘streaming.php‘, fucntion(data) {    alert("Received" + data);}, function(data) {    alert("Done!");});

4 伺服器發送事件

        SSE(Server-Sent Events,伺服器發送事件)是圍繞唯讀Comet互動推出的API或者模式。

5 Web Sockets

        WebSockets的目標是在一個單獨持久的串連上提供全雙工系統、雙向通訊。在JavaScript中建立了WebSocket之後,會有一個HTTP請求發送到瀏覽器以發起串連。在取得伺服器響應後,建立的連結會使用HTTP升級從HTTP協議交換為WebSocket協議。

        由於WebSockets使用了自訂的協議,所以URL模式也略有不同。未加密的串連不再是http://,而是ws://;加密的串連也不是https://,而是wss://。在使用WebSocket URL時,必須帶著這個模式,因為將來還有可能支援其他模式。

        使用自訂協議而非HTTP協議的好處是,能夠在用戶端和伺服器端之間發送非常少量的資料,而不必擔心HTTP那樣位元組級的開銷。

六、安全

        對於未被授權系統有權訪問某個資源的情況,我們稱之為CSRF(Cross-Site Request Forgery,跨網站請求偽造)。為確保通過XHR訪問的URL安全,通行的做法就是驗證寄件者是否有許可權訪問響應的資源。有下列幾種方式可供選擇:

  • 要求以SSL串連來訪問可以通過XHR請求的資源。
  • 要求每一次請求都要附帶經過相應計算得到的驗證碼。

        以下措施對防範CSRF攻擊不起作用。

  • 要求發送POST而不是GET請求——很容易改變。
  • 檢查來源URL以確定是否可信——來源記錄很容易偽造。
  • 基於cookie資訊進行驗證——同樣很容易偽造。

[筆記]《JavaScript進階程式設計》- Ajax與Comet

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.