關於cometd的一些經驗總結-js端

一:js端使用方式 

=================================================== 
第一步 :初始化cometd配置, 
            $.cometd.configure({ 
                url: cometdURL, 
                logLevel: 'debug' 
            }); 
有兩種方式: 
=================================================== 
一:經過 URL string 
cometd.configure('http://localhost:8080/cometd'); 
二:經過配置對象的方式: 
cometd.configure({ 
url: 'http://localhost:8080/cometd' 
}); 
經過第二種方式配置cometd時,對象屬性以下: 
url:鏈接URL 
logLevel:日誌級別,默認爲info,可支持warn、info、debug 
maxConnections:客戶端鏈接到cometd服務端最大鏈接數量,默認爲2,根據瀏覽器的不一樣,能夠更改瀏覽器默認支持最大鏈接的相應值 
backoffIncrement:與服務器鏈接失敗後,等待重連的增量時間,默認爲1000,單位爲毫秒。如:第一次重連爲1s,則第二次重連爲2s之後,第三次3s,以此類推 
maxBackoff:最大重連增量時間,默認爲60000ms 
reverseIncomingExtensions: 
maxNetworkDelay:一個request請求鏈接服務器失敗的最大等待時間,默認爲10000ms 
requestHeaders:request請求頭,默認爲{} 
appendMessageTypeToURL:是否支持Bayeux消息類型能夠被附加到URL上併發送至服務器,默認爲true 
autoBatch:當沒有手動指定批次處理一批publish通信消息時,是否支持默認的批處理,默認爲false 


=================================================== 
第二步:調用 $.cometd.handshake()方法,與服務器通信握手 
=================================================== 

調用configure後,並無啓動Bayeux Communication,須要手動調用comted.handshake()進行通信握手,通信握手作了兩件事情: 
1.客戶端與服務器協定通信協議類型 
2.通信協議類型達成一致後,服務端通知客戶端詳細的請求時間 

該方法是一個異步方法,在通信握手完成後會當即返回,可是handshake返回後並不表明鏈接已經創建,通信握手失敗緣由可能有以下幾個: 
1.輸錯了訪問的URL 
2.客戶端與服務器沒有交換成功通信協議 
3.服務器拒絕通信握手,例如:證書認證失敗等 
4.服務器down掉 
5.網絡傳輸失敗 
另外:cometd提供init()方法,集成了configure和handshake方法 

因爲handshake是異步的方法,你沒法獲知鏈接是否創建成功,即便創建成功,客戶端也有可能被中斷,例如服務器down機等緣由。cometd提供了監聽機制,用來監聽鏈接等特殊通道的狀態 

=================================================== 
第三步:訂閱消息通道Channels,創建監聽 
subscribe 訂閱普統統道消息、service通道消息 
addListener 監聽meta channels消息 
=================================================== 
Bayeux 對Channels定義爲:Channels相似於一個消息主題,有興趣的人能夠訂閱該消息通道,並接收消息通道發佈過來的消息。 
Channels有三種: 
1.meta channels(元數據channel,全部此種channel都以/meta開頭) 
2.service channels(服務channel,全部此種channel都以/service開頭) 
3.normal channels(普通channel) 
每一個channel相似於一個目錄的路徑,例如/meta/connect 
&& meta channels 

meta channels是由Bayeux 協議自身創建的,開發時不能subscribe一個meta channel,不然服務器迴響應錯誤的信息,可是你能夠在meta channel上創建一個監聽 
向一個meta channels發送消息是毫無心義的,只有Bayeux協議建立並在meta channel上面傳輸信息 
meta channels一般用在客戶端監聽錯誤信息上,例如:通信握手錯誤,網絡鏈接錯誤等。 


&& service channels 
service channels 一般用在服務端與客戶端request/response通信模式下,它與消息通知/訂閱通信模式與普通channel大相徑庭。 
當訂閱服務通道而且沒有獲得錯誤的響應時,此時服務端未處理任何操做,而且忽略了訂閱請求。 
你可使用一個服務器與客戶端之間特定的語義,將消息發佈到service channels。 
service channels一般用來實現私聊。 

&& normal channels 
普通channels一般創建一個消息主題,並使用在publish/subscribe通信模式下。你能夠在普通channel上進行訂閱及消息發佈。 
普通channel一般用來向全部訂閱的客戶端發送主題消息,例如當股票價格發生波動的時候。 

addListener()方法: 
1.必須用在監聽meta channels消息 
2.可能會用在監聽service channels消息,(也可使用subscribe()方法,可是不被推薦使用) 
3.不能用來監聽normal channels消息,(通常使用subscribe()方法來替代) 
4.不能涉及任何與服務器的通信,這樣能夠在調用handshake()以前調用。 
5.是一個同步方法, 當它返回值時,必須保證listener已經添加。 

subscribe()方法: 
1.不能用在監聽meta channels消息,不然服務器回返回錯誤。 
2.可能會用在監聽service channels消息,(也可使用addListener()方法,推薦使用) 
3.用來監聽normal channels消息 
4.包含於服務器的通信,在handshake被調用以前不能調用它 
5.是一個異步的方法,在服務器收到並處理訂閱請求以前當即返回。 

注意:調用subscribe方法並不意味着當該方法返回值的時候你已經完成了服務器的訂閱。 
addListener和subscribe方法分別返回兩個訂閱對象能夠傳遞給removeListener()和unsubscribe()方法。 

// Some initialization code 
var subscription1 = cometd.addListener('/meta/connect', function() { ... }); 
var subscription2 = cometd.subscribe('/foo/bar/', function() { ... }); 

// Some de-initialization code 
cometd.unsubscribe(subscription2); 
cometd.removeListener(subscription1); 

///////////////////////////////////// 
var _subscription; 

// The idempotent method 
function _refresh() 

    _appUnsubscribe(); 
    _appSubscribe(); 


function _appUnsubscribe() 

    if (_subscription) 
        cometd.unsubscribe(_subscription); 
    _subscription = null; 


function _appSubscribe() 

    _subscription = cometd.subscribe('/foo/bar', function() { ... }); 

//////////////////////////////////////// 
值得注意的是,你要當心處理你的應用。爲了不泄露函數調用或者避免函數屢次調用(一旦你屢次錯誤的綁定了相同的回調函數) 
當服務器端未返回信息時(網絡中斷或者服務器crash時),subscribe和unsubscribe方法會有什麼樣的行爲? 
subscribe:本地監聽者首先加入到channel中的訂閱者列表中,而後與服務器通信。若是通信失敗,服務器並不知道須要向客戶端發送數據所以客戶端本地的監聽者並不會被反調。 
unsubscribe:本地監聽者首先從channel中斷訂閱者列表中移除。而後嘗試與服務器通信。若是通信失敗,服務器仍然發送信息到客戶端,可是本地並無響應監聽可指達。 

關於監聽者異常處理問題: 
若是監聽者/訂閱者函數拋出異常,錯誤信息會以debug級別打印日誌。然而,你能夠定義一個全局異常監聽處理函數來截獲異常信息。 
當監聽者或者訂閱者每次拋出異常時該全局方法都會被反調。 
cometd.onListenerException = function(exception, subscriptionHandle, isListener, message) 

    // Uh-oh, something went wrong, disable this listener/subscriber 
    // Object "this" points to the CometD object 
    if (isListener) 
        this.removeListener(subscriptionHandle); 
    else 
        this.unsubscribe(subscriptionHandle); 

全局異常監聽機制可能會向服務端發送消息。若是異常監聽處理函數拋出了異常,異常會以info級別的日誌形式 
打印出來,Cometd框架不會break掉。 

//////////////////////////////////// 
使用通配符能夠同時訂閱多個渠道,例如: 
cometd.subscribe("/chatrooms/*", function(message) { ... }); 
單個星號統配單一渠道段,如:/chatrooms/12 /chatrooms/15 不支持/chatrooms/12/upload 
爲了統配多渠道段,可使用雙星號,如: 
cometd.subscribe("/events/**", function(message) { ... }); 
使用多渠道可支持相似/events/12/upload events/12 events/12/upload/abc等通道 
通配符原理一樣應用在監聽者中,例如: 
cometd.addListener("/meta/*", function(message) { ... }); 
默認的,訂閱總體通配符/*和/**會發生錯誤,通配符只能放在分段的最後面。 

目前爲止最有趣的meta channels 是 /meta/connect,由於服務器能夠返回當前鏈接的狀態。 
值得一提的是,meta/connect也被用於長輪詢服務器。所以,若是在一個有效的輪詢中發佈一個斷開消息, 
服務器會返回該poll並觸發/meta/connect linstener。 


============================================================= 
第四步 調用publish方法向通道中發佈消息 
============================================================= 
publish方法容許你向某一特定的channel中發佈消息 
cometd.publish('/mychannel', { mydata: { foo: 'bar' } }); 
不能發佈消息到meta channel,可是能夠發佈消息到一個未訂閱的channel,前提是你已經handshake了 
publish是一個異步的通信方法,在服務器收到消息以前它會當即返回。 

============================================================= 
關於disconnecting 
============================================================= 
cometd js api提供了自動重連功能當網絡或服務器鏈接失敗時。重連參數在configuration中配置 

1.短暫網絡鏈接失敗 
一旦發生網絡暫時鏈接失敗,客戶端會經過/meta/connect通道發佈消息,並將successful標誌位置爲false。 
此時服務器會保持客戶端的狀態,一旦網絡回覆鏈接,服務器會恢復鏈接就像未發生中斷同樣。 
客戶端在這種狀況下,僅僅須要從新創建長輪詢,可是在網絡中斷期間發佈給服務器的消息不會被重發。 
2.長時間網絡異常或服務器異常 
若是網絡鏈接長時間異常,服務器將會超時並失去客戶端鏈接,並刪除與之相關的狀態。 
在這種狀況下,客戶端的重連機制將會執行如下步驟: 
。。長輪詢試圖從新創建,可是服務器拒絕訪問並返回402::Unknown client錯誤信息 
。。通信握手試圖從新創建,服務器一般會接收,並從新創建一個鏈接 
。。在通信握手創建成功的基礎上,長鏈接從新創建。 


若是註冊了meta channels,瞭解這些步驟,由於從新鏈接可能會涉及多個服務器的消息交換。 


調用disconnect函數致使消息被髮送給Bayeux服務端,以便服務端清理關於該客戶端的狀態維護。 
正如全部涉及到與服務器通信的方法同樣,它是一個異步的方法。若是服務器並未返回,js端將會中止全部的試圖的鏈接,而且清理本地狀態。 
無論disconnect方法返回成功或者失敗,該方法都是安全的。客戶端不管如何都會disconnect,它的本地狀態會被清理掉。 
若是服務器沒有返回值,最終該客戶端將會被超時處理,而且清理服務端的狀態。 


============================================================= 
關於message bantching 
============================================================= 
咱們常常須要向服務器不一樣的渠道同時發送數據。因爲publish方法是異步的,同時向服務器端發佈屢次時,並不能一塊兒發佈並依次返回。 
咱們曾天真的這樣處理: 
cometd.handshake(); 

// Warning: non-optimal code 
cometd.publish('/channel1', { product: 'foo' }); 
cometd.publish('/channel2', { notificationType: 'all' }); 
cometd.publish('/channel3', { update: false }); 
你可能認爲,三個publish方法會相繼的從客戶端發出,可是實際並不是如此。publish方法是異步的,它會當即返回值。所以3個publish方法可能在未返回任何數據以前到達網絡。 
以上發生的是,第一個publish方法會當即執行,另外兩個放入隊列中,等待第一個publish執行完成。 
當服務端接收到publish發送過來的消息時,第一個publish執行完成,服務器返回meta信息給客戶端。客戶端接收該信息並完成publish方法。 
當第一個publish完成後,第二個被執行並等待完成,以後第三個被執行。 

若是configuration參數autoBatch設置爲true,應用程序會自動執行批次裏面已排隊的消息。 
所以,在上面的例子中,若是autoBatch設置了true,第一個publish方法會當即被執行,當它執行完成後, 
應用程序會將第二個和第三個publish打包成一個請求發送到服務器。 
這種排隊機制是爲了不在長輪詢後面發起publish隊列,若是沒有這個機制,瀏覽器會受到3個發佈請求,可是隻能有2個連接,
一個是已經被佔用的長輪詢請求。所以瀏覽器可能會決定循環發送request,因此第一個publish發生在第二個鏈接中(第一個已經 
忙於長輪詢請求),調度第二個publish使用第一個鏈接,第三個publish使用第二個鏈接,當第一個publish返回後。 
結果是,若是你有一個超時時間爲5分鐘的長鏈接,第二個publish請求可能比第一個和第三個publish晚5分鐘到達服務器。 
你可使用batching優化這三個publish請求,經過將消息綁定成組造成一個單一的Bayeux消息。 

cometd.handshake(); 

cometd.batch(function() 

    cometd.publish('/channel1', { product: 'foo' }); 
    cometd.publish('/channel2', { notificationType: 'all' }); 
    cometd.publish('/channel3', { update: false }); 
}); 

// Alternatively, but not recommended 
cometd.startBatch() 
cometd.publish('/channel1', { product: 'foo' }); 
cometd.publish('/channel2', { notificationType: 'all' }); 
cometd.publish('/channel3', { update: false }); 
cometd.endBatch() 

當一個batch啓動後,隨後的API調用將再也不發送到服務器,而是會排隊等候,直到batch結束。 
batch將全部的排隊等候的message包裝成單一的一個Bayeux消息併發送至Bayeux服務器。 
消息綁定有效的利用了網絡,將三個request/response生命週期縮短成一個。 

============================================================= 
關於transports 
============================================================= 
Bayeux規範定義了兩個強制性的傳輸協議: 
long-polling和callbak-polling 
cometd實現了這兩個協議,並支持websocket協議。 
最新的瀏覽器(如火狐3.5+),也有可能使用長輪詢通訊及跨站點通信。 

1.long-polling transport 
long-polling transport是瀏覽器和服務器之間默認的通信協議,若是不支持websocket的話。 
該協議應用在跨域名及相同域名的客戶端、服務器通信。數據類型被組織成text/json格式並經過一個普通的XMLHttpRequest推送至服務器。 
2.callback-polling transport 
callback-polling transport應用在跨域名通信。衆所周知,XMLHttpRequest訪問不一樣域中的腳本是有限制的。 
web

相關文章
相關標籤/搜索