原文地址: http:///documentation/cometd-javascript/subscription
CometD的JavaScript訂閱 raman在周一,2009年6月29日 - 15:29提交。 JavaScript的CometD API:訂閱和取消訂閱 頻道 Bayeux規(guī)范定義了頻道的概念:它像一個(gè)消息的主題,有興趣的人士可以訂閱接收到頻道發(fā)布的信息。 有3種類型的渠道: 元數(shù)據(jù)頻道 服務(wù)頻道 正常頻道 一個(gè)頻道看起來像一個(gè)目錄路徑,如/meta/connect(元數(shù)據(jù)頻道;所有的元數(shù)據(jù)頻道的前綴都是/meta/開始的),或/service/chat(服務(wù)頻道;所有服務(wù)頻道的前綴都是/service/開始的)或/foo/bar(正常頻道)。 元數(shù)據(jù)頻道 元數(shù)據(jù)頻道由Bayeux協(xié)議本身創(chuàng)建。 訂閱元數(shù)據(jù)頻道這是不可能的:服務(wù)器將回復(fù)一條錯(cuò)誤消息。但是,它可能監(jiān)聽元數(shù)據(jù)頻道(見下文訂閱和監(jiān)聽之間的差異)。 發(fā)布消息到元數(shù)據(jù)頻道是沒有意義的:只有Bayeux協(xié)議實(shí)現(xiàn)創(chuàng)建和發(fā)送元數(shù)據(jù)頻道的消息。 元數(shù)據(jù)頻道對(duì)客戶端監(jiān)聽錯(cuò)誤消息是非常有用的,像握手錯(cuò)誤(例如,因?yàn)榭蛻舳藳]有提供正確的憑據(jù))或網(wǎng)絡(luò)錯(cuò)誤(例如,知道什么時(shí)候與服務(wù)器的連接斷開了,或它已經(jīng)重新建立了)。 服務(wù)頻道 服務(wù)頻道在客戶端和服務(wù)器以請求/響應(yīng)的方式進(jìn)行通信的情況下使用(對(duì)應(yīng)于發(fā)布/訂閱的方式進(jìn)行通信或正常頻道)。 訂閱服務(wù)頻道不會(huì)得到錯(cuò)誤,這相當(dāng)于對(duì)服務(wù)器沒有操作:服務(wù)器會(huì)忽略訂閱請求。 它可以用特定的客戶端(一個(gè)發(fā)布消息到服務(wù)頻道的客戶端)和服務(wù)器之間通信的語義發(fā)布消息到服務(wù)頻道。 服務(wù)頻道是很有用的實(shí)現(xiàn),例如,私人聊天消息:在與userA,userB和userC聊天,userA可以使用服務(wù)頻道發(fā)布私人消息給userC(UserB不會(huì)知道)。 正常頻道 正常頻道,有一個(gè)消息主題的語義,并在發(fā)布/訂閱的通信方式情況下使用。 通常情況下,是可以訂閱正常頻道和發(fā)布消息到正常頻道的,只有在bayeux服務(wù)器上使用了安全策略才會(huì)禁止。 正常頻道在實(shí)現(xiàn)廣播消息給所有訂閱的客戶中是非常有用的,例如,在股票價(jià)格變動(dòng)的情況下。 訂閱者與聽眾 JavaScript的CometD API有2個(gè)API來讓頻道訂閱工作: addListener()和removeListener() subscribe()和unsubscribe() addListener()方法: 監(jiān)聽元數(shù)據(jù)頻道的消息必須使用 可用于收聽服務(wù)頻道消息(你也可以使用subscribe()) 不應(yīng)該用來聽正常頻道消息(使用subscribe()代替) 不涉及任何與bayeux服務(wù)器的通信,因此可以調(diào)用之前稱為握手的handshake() 是同步的:當(dāng)它返回時(shí),要保證監(jiān)聽已添加 subscribe()方法: 不得用于收聽元數(shù)據(jù)頻道消息(否則服務(wù)器將返回一個(gè)錯(cuò)誤) 可用于收聽服務(wù)頻道消息(你也可以使用addListener()) 應(yīng)該用來監(jiān)聽正常頻道消息 涉及bayeux服務(wù)器的通信,因此不能在調(diào)用握手handshake()之前調(diào)用 是異步的:它會(huì)立即返回,在bayeux服務(wù)器已收到訂閱請求之前 請注意: 調(diào)用subscribe(),當(dāng)subscribe()返回時(shí),并不意味著您已經(jīng)完成了與服務(wù)器的訂閱。 addListener()和subscribe()都返回一個(gè)訂閱對(duì)象,必須分別通過removeListener()和unsubscribe()來取消訂閱: / /一些初始化代碼 var subscription1
= cometd.addListener('/meta/connect', function() { ... }); var subscription2
= cometd.subscribe('/foo/bar/', function() { ... }); / /一些初始化代碼 cometd.unsubscribe(subscription2); cometd.removeListener(subscription1); 一個(gè)常見的模式是利用冪等方法來處理,像這樣: 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() { ... }); } 當(dāng)然,同樣也適用于addListener()/ removeListener()。 需要指出的是,你要小心你的應(yīng)用程序:你一定要取消訂閱,以避免泄漏函數(shù)或不止一次執(zhí)行函數(shù)(因?yàn)槟憧赡軙?huì)錯(cuò)誤地綁定兩次相同的回調(diào))。 請參閱討論有關(guān)使用冪等方法的思想。 在bayeux服務(wù)器不可達(dá)的情況下,怎么處理subscribe()和unsubscribe()(由于網(wǎng)絡(luò)故障,或因?yàn)榉?wù)器崩潰)? 在subscribe()中。本地監(jiān)聽是第一個(gè)加入到該頻道的用戶列表的,然后服務(wù)器企圖與它進(jìn)行通信。如果通信失敗,服務(wù)器將不知道,它已經(jīng)將消息發(fā)送到這個(gè)客戶端,因此客戶端上的本地監(jiān)聽(雖然目前還是)將永遠(yuǎn)不會(huì)被調(diào)用。 在unsubscribe(),本地監(jiān)聽是首次從該頻道的用戶列表中刪除的,然后服務(wù)器企圖與它通信。如果通信失敗,服務(wù)器仍然會(huì)發(fā)送消息到客戶端,但不會(huì)有本地監(jiān)聽派遣。 偵聽/訂閱的異常處理 如果偵聽或訂閱函數(shù)拋出一個(gè)異常(例如,調(diào)用一個(gè)未定義的對(duì)象,方法等),然后記錄錯(cuò)誤消息(“調(diào)試”級(jí)別)。 然而,有一種方法:定義一個(gè)全局監(jiān)聽器的異常處理程序,攔截每次偵聽或訂閱拋出的異常: 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); } 監(jiān)聽器的異常處理程序可以發(fā)送消息到服務(wù)器。 如果監(jiān)聽器異常處理程序本身拋出一個(gè)異常,這個(gè)異常記錄為“信息”且不破壞CometD實(shí)現(xiàn)。 需要注意的是有一個(gè)類似的機(jī)制擴(kuò)展存在, 在http:///documentation/cometd/ext可以看到。 通配符訂閱 可以一次使用通配符來訂閱幾個(gè)頻道,比如: cometd.subscribe("/chatrooms/*",
function(message) { ... }); 一個(gè)星號(hào)的意思是匹配一個(gè)單一頻道段,所以在上面的例子,它將匹配頻道/chatrooms/12 和 /chatrooms/15, 而不是 /chatrooms/12/upload。 為了匹配多個(gè)頻道細(xì)分,使用兩個(gè)星號(hào): cometd.subscribe("/events/**",
function(message) { ... }); 兩個(gè)星號(hào)將匹配/events/stock/FOO 和 /events/forex/EUR, 以及 /events/feed 和 /events/feed/2009/08/03。 通配符機(jī)制也適用于偵聽,因此很這樣可能偵聽所有的元數(shù)據(jù)頻道: cometd.addListener("/meta/*",
function(message) { ... }); 默認(rèn)情況下,訂閱全局通配符/ * / **返回的結(jié)果是一個(gè)錯(cuò)誤,但這種行為在通過給bayeux服務(wù)器指定一個(gè)自定義安全政策來改變。 通配符只能被指定在頻道的最后部分,所以這些都是無效的訂閱:/ ** / foo或/ foo /*/bar。 元數(shù)據(jù)頻道列表 這些都是在JavaScript CometD實(shí)現(xiàn)的元數(shù)據(jù)頻道: /meta/handshake /meta/connect /meta/disconnect /meta/subscribe /meta/unsubscribe /meta/publish /meta/unsuccessful 當(dāng)記錄的bayeux消息由JavaScript Cometd實(shí)現(xiàn)處理時(shí),每一個(gè)元數(shù)據(jù)頻道就會(huì)被通知。 有任何失敗都會(huì)通知/meta/unsuccessful頻道。 到目前為止,最有趣的是訂閱/meta/connect元數(shù)據(jù)頻道,因?yàn)樗芊祷嘏cbayeux服務(wù)器的當(dāng)前連接狀態(tài)。它可以和/meta/disconnect組合使用。例如,根據(jù)bayeux服務(wù)器上的連接狀態(tài),在頁面上顯示一個(gè)綠色的“連接”圖標(biāo)或一個(gè)紅色的“斷開”圖標(biāo),。 使用/meta/connect ,/meta/disconnect頻道,這是一種常見的模式: var _connected =
false; cometd.addListener('/meta/connect',
function(message) { // if (cometd.getStatus() == 'disconnecting'
|| cometd.getStatus() == 'disconnected') if (cometd.isDisconnected()) // Available
since 1.1.2 { return; } var wasConnected = _connected; _connected = message.successful; if (!wasConnected && _connected) { // Reconnected } else if (wasConnected &&
!_connected) { // Disconnected } }); cometd.addListener('/meta/disconnect',
function(message) { if (message.successful) { _connected = false; } } /meta/connect頻道的一個(gè)小的需要注意的是/meta/connect是使用輪詢服務(wù)器。 因此,如果斷開是在一個(gè)活動(dòng)的輪詢期間,這個(gè)輪詢將被服務(wù)器返回,并觸發(fā)/meta/connect監(jiān)聽器。 執(zhí)行連接邏輯前不進(jìn)行狀態(tài)的初步檢查驗(yàn)證。 元數(shù)據(jù)頻道的另一種有趣的用法是在握手時(shí),有一個(gè)身份驗(yàn)證步驟。 在注冊/meta/handshake頻道情況下,可以返回相關(guān)細(xì)節(jié),例如,驗(yàn)證失敗的細(xì)節(jié)。 |
|