Ajax和Comet技術總結

NO IMAGE

Ajax是一種技術,一種能夠向伺服器請求額外的資料而無需解除安裝頁面的技術,能夠使網頁具備更優的使用者體驗。Ajax技術的核心是XMLHttpRequest物件(XHR)。本文從XHR開始談起,理解Ajax技術的特點,再對跨域以及Comet等技術進行簡要理解和總結。

XMLHttpRequest基本用法

XHR物件有兩個常用的方法open和send。open方法使用者啟動一個HTTP請求,不過它不會真的傳送HTTP請求。open方法接收3個引數,分別表示請求的HTTP方法、請求的URL、是否非同步。XHR物件的第二個方法send用於傳送open所啟動的請求。send方法接收1個引數,表示HTTP請求的主體資料。如果傳送的是GET請求這種沒有附帶主體資料的HTTP請求,則傳入null即可。如果是POST請求,則傳入需要POST的資料。下面是一個簡單示例,向/api/data發起一個GET請求,並且是採取非同步的方式傳送請求,即該請求不會阻塞頁面中其他js程式碼的執行。


var xhr = new XMLHttpRequest()
xhr.open("get", "/api/data", true)
xhr.send(null)

請求得到的響應資料會自動填充到XHR物件的屬性上,主要有下面4個屬性:

* responseText: 響應主體文字
* responseXML: 如果響應內容型別是”text/xml”或”application/xml”, 這個屬性中將包含響應資料的XML DOM文件
* status: 響應的HTTP狀態碼,一般可以將HTTP狀態嗎200視為成功的標識
* statusText: HTTP狀態的說明

XHR物件有1個readyState屬性記錄了該物件從建立到收到響應資料可能會經歷的5種狀態,readyState的可能取值如下:

0: 還沒有呼叫open()方法初始化請求

1: 已經呼叫open()方法但是還沒有呼叫send()方法

2: 已經呼叫send()方法但是還沒有收到響應

3: 收到部分響應資料,還有部分資料沒收到

4: 收到全部響應資料,即響應結束,資料完備

當readyState從一個值變到另一個值的時候會觸發readystatechange事件,當這個事件觸發的時候只需要在事件處理器裡面檢查一下readyState的值是否為4,當其值為4的時候就可以對響應的資料做後續處理了。給readystatechange事件指定處理器必須在呼叫open()方法之前完成才能確保跨瀏覽器相容性。下面是簡單示例。


var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
console.log(xhr.status, xhr.responseText)
}
}
xhr.open("get", "/api/data", true)
xhr.send(null)

XHR物件提供setRequestHeader()方法可以設定請求的自定義HTTP頭部資訊,該方法接收兩個引數,要設定的欄位和該欄位的值。在呼叫open()啟動一個請求之後並且在send()傳送請求之前呼叫setRequestHeader()才能設定成功。請求得到響應之後,可以通過getResponseHeader()方法獲取響應的HTTP頭部資訊,該方法接收1個引數,即要獲取的欄位名。而通過getAllResponseHeaders()則可以獲得所有頭部資訊組成的長字串。下面是簡單示例。


var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
console.log(xhr.status, xhr.responseText)
console.log(xhr.getResponseHeader('SomeKey'))
console.log(xhr.getAllResponseHeaders())
}
}
xhr.open("get", "/api/data", true)
xhr.setRequestHeader("SomeKey", "SomeValue")
xhr.send(null)

FormData

XMLHttpRequest 2級定義了FormData型別為序列化表單、建立與表單格式相同的資料、用於XHR傳輸提供便利。FormData提供append()方法可以直接新增資料,該方法接收兩個引數鍵和值。FormData的建構函式可以不傳引數,也可以直接傳入1個表單元素。傳入表單元素之後會利用該表單元素的資料來向FormData物件預先填入鍵值對。下面是簡單示例。


var form = document.getElementById('myForm')
var data = new FormData(form)
data.append('someKey', 'someValue')
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
console.log(xhr.responseText)
}
}
xhr.open('post', '/api/upload', true)
xhr.send(data)

跨域資源共享

通過XHR實現Ajax通訊會遇到一個限制,即跨域安全策略。跨域安全策略限制了“相同域名、相同埠、相同協議”,當XHR想要訪問限制之外的資源就會引發安全錯誤。CORS(Cross-Origin Resource Sharing),跨域資源共享,其思想是通過使用自定義HTTP頭部讓瀏覽器與伺服器進行溝通從而決定請求或者響應的成功與失敗,需要瀏覽器和伺服器同時支援才能實現正常的訪問。目前大部分瀏覽器已經支援了CORS,所以寫起程式碼跟普通的同域資源訪問幾乎一樣,就只是把URL用絕對路徑表示。因此,要實現跨域的關鍵還是在伺服器,具體如何實現本文不深入討論。下面是前端js的簡單示例。


var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
console.log(xhr.responseText)
}
}
xhr.open('get', 'http://www.otherserver.com/api/data', true)
xhr.send(null)

JSONP

JSONP(JSON with padding)是應用JSON實現跨域資源訪問的一種方法。JSONP由兩部分內容組成:回撥函式和JSON資料。前面說過,XHR請求會遇到跨域安全策略的限制,但是HTML中的script標籤則不會有這個限制,我們可以通過script標籤引用不同域裡面的js檔案。JSONP便是鑽了這個空子,它通過動態建立script元素,然後把src指向其他域的URL從而實現載入其他域的資源,然後通過回撥函式來處理載入得到的資料。下面是一個簡單示例。


function handler(res) {
console.log(res)
}
var script = document.createElement('script')
script.src = 'http://www.otherserver.com/api/data/?callback=handler'
document.body.insertBefore(script, document.body.firstChild)

上述程式碼指定了動態建立的script元素的src為另一個域名下面的/api/data,然後指明回撥函式為handler。將script插入到DOM裡面之後會向對應的URL載入資料,完成之後會將得到的JSON資料解析成一個物件並呼叫handler進行處理。

JSONP是實現跨域訪問的一種簡單的方法,不過也存在一些安全問題,例如請求的其他域的URL響應給你一段惡意程式碼。JSONP還有一個問題,script標籤引用的是js,json由於被js所支援所以也可以引用,因此在請求其他域的URL時需要確認它是否以json格式進行響應,而不是XML。

Comet

Ajax是一種從網頁向伺服器請求資料的技術,而Comet與之相反,它是從伺服器向網頁推送資料的技術,適用於實時性要求比較高的應用。實現Comet的方式有兩種:長輪詢和流。在說長輪詢之前先說一下短輪詢,它的思路很簡單,就是客戶端使用定時器,每隔一定的時間間隔就向伺服器傳送Ajax請求看看有沒有資料更新,這個時間間隔一般很小。長輪詢同樣也是客戶端不斷向伺服器傳送請求,不同的是,客戶端不需要按照時間間隔不斷地傳送請求,而是發起1個請求到伺服器之後,客戶端和伺服器之間的HTTP連線保持開啟,直到伺服器有資料更新就通過這個連線向客戶端響應資料,然後再關閉這個HTTP連線。關閉之後瀏覽器再發起一個新的連線繼續重複前面的過程。相比短輪詢,長輪詢發起的HTTP連線次數更少了,不過如果HTTP連線長時間保持開放也是在佔用伺服器的資源。

第二種實現Comet的方式是基於HTTP流,客戶端向伺服器發起1個HTTP連線,全程保持這個連線開啟,客戶端週期性地通過這個連線向伺服器獲取資料檢視更新。

SSE

SSE(Server-Send Events),伺服器傳送事件,是一種實現Comet互動的瀏覽器API,支援輪詢也支援HTTP流。SSE API用於建立到伺服器的單向連線,伺服器通過這個連線可以傳送任意數量的資料給客戶端。伺服器響應的MIME型別為text/event-stream。下面是SSE的JavaScript API的簡單示例。


var source = new EventSource("/api/events")
source.onmessage = function(event) {
console.log(event.data)
}

如上面程式碼所示,要向伺服器預定事件流獲取伺服器傳送的資料,首先建立EventSource物件,然後在message事件觸發的時候進行處理。伺服器傳送的資料以字串形式儲存在event.data中。EventSource物件會保持與伺服器的活動連線,如果中間斷開會重新連線,如果要真正地斷開連線可以通過呼叫close()方法來實現。EventSource的message事件會在從伺服器收到新事件的時候觸發,除了message事件之外它還有另外2個事件open和error,open事件在建立連線的時候觸發,error事件在無法建立連線的時候觸發。

Web Sockets

Web Sockets是一種與伺服器進行全雙工雙向通訊的通道。Web Sockets不適用HTTP協議,而前面說的Ajax和Comet都是使用HTTP協議。篇幅關係本文對Web Sockets不作討論。

總結

Ajax實現在不載入頁面的情況下向伺服器請求資料,提升網頁的使用者體驗。實現Ajax技術的XHR會遇到跨域安全策略的限制,通過CORS解決跨域問題需要瀏覽器和伺服器兩端的配合。JSONP是一種實現跨域訪問的”小技巧“但也是存在一些問題。Comet對Ajax進行了拓展,讓伺服器能夠實時向瀏覽器推送資料,但從實現來看不管是輪詢還是HTTP流,都是瀏覽器先向伺服器發起請求連線。Web Sockets的全雙工雙向通訊也有其特色,以後有時間可以繼續瞭解。

以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支援指令碼之家!

您可能感興趣的文章:

詳解Tomcat如何實現CometJavaScript資料推送Comet技術詳解使用Java實現類似Comet風格的web app頁面間隔半秒鐘更新時間 Asp.net使用Comet開發http長連線示例分享BitComet 0.89 去廣告簡潔優化版 下載jQuery Ajax全解析jquery實現ajax提交form表單的方法總結jquery ajax例子返回值詳解基於JQuery框架的AJAX例項程式碼完美解決AJAX跨域問題