原文地址:
http://cometd.org/documentation/cometd-javascript/subscription
CometD的JavaScript訂閱
raman在周一,2009年6月29日 - 15:29提交。
JavaScript的CometD API:訂閱和取消訂閱
頻道
Bayeux規(guī)范定義了頻道的概念:它像一個(gè)消息的主題,有興趣的人士可以訂閱接收到頻道發(fā)布的信息。
有3種類型的渠道:
元數(shù)據(jù)頻道
服務(wù)頻道
正常頻道
一個(gè)頻道看起來(lái)像一個(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ù)器以請(qǐng)求/響應(yīng)的方式進(jìn)行通信的情況下使用(對(duì)應(yīng)于發(fā)布/訂閱的方式進(jìn)行通信或正常頻道)。
訂閱服務(wù)頻道不會(huì)得到錯(cuò)誤,這相當(dāng)于對(duì)服務(wù)器沒有操作:服務(wù)器會(huì)忽略訂閱請(qǐng)求。
它可以用特定的客戶端(一個(gè)發(fā)布消息到服務(wù)頻道的客戶端)和服務(wù)器之間通信的語(yǔ)義發(fā)布消息到服務(wù)頻道。
服務(wù)頻道是很有用的實(shí)現(xiàn),例如,私人聊天消息:在與userA,userB和userC聊天,userA可以使用服務(wù)頻道發(fā)布私人消息給userC(UserB不會(huì)知道)。
正常頻道
正常頻道,有一個(gè)消息主題的語(yǔ)義,并在發(fā)布/訂閱的通信方式情況下使用。
通常情況下,是可以訂閱正常頻道和發(fā)布消息到正常頻道的,只有在bayeux服務(wù)器上使用了安全策略才會(huì)禁止。
正常頻道在實(shí)現(xiàn)廣播消息給所有訂閱的客戶中是非常有用的,例如,在股票價(jià)格變動(dòng)的情況下。
訂閱者與聽眾
JavaScript的CometD API有2個(gè)API來(lái)讓頻道訂閱工作:
addListener()和removeListener()
subscribe()和unsubscribe()
addListener()方法:
監(jiān)聽元數(shù)據(jù)頻道的消息必須使用
可用于收聽服務(wù)頻道消息(你也可以使用subscribe())
不應(yīng)該用來(lái)聽正常頻道消息(使用subscribe()代替)
不涉及任何與bayeux服務(wù)器的通信,因此可以調(diào)用之前稱為握手的handshake()
是同步的:當(dāng)它返回時(shí),要保證監(jiān)聽已添加
subscribe()方法:
不得用于收聽元數(shù)據(jù)頻道消息(否則服務(wù)器將返回一個(gè)錯(cuò)誤)
可用于收聽服務(wù)頻道消息(你也可以使用addListener())
應(yīng)該用來(lái)監(jiān)聽正常頻道消息
涉及bayeux服務(wù)器的通信,因此不能在調(diào)用握手handshake()之前調(diào)用
是異步的:它會(huì)立即返回,在bayeux服務(wù)器已收到訂閱請(qǐng)求之前
請(qǐng)注意:
調(diào)用subscribe(),當(dāng)subscribe()返回時(shí),并不意味著您已經(jīng)完成了與服務(wù)器的訂閱。
addListener()和subscribe()都返回一個(gè)訂閱對(duì)象,必須分別通過removeListener()和unsubscribe()來(lái)取消訂閱:
/ /一些初始化代碼
var subscription1= cometd.addListener('/meta/connect', function() { ... });
var subscription2= cometd.subscribe('/foo/bar/', function() { ... });
/ /一些初始化代碼
cometd.unsubscribe(subscription2);
cometd.removeListener(subscription1);
一個(gè)常見的模式是利用冪等方法來(lái)處理,像這樣:
var _subscription;
// The idempotentmethod
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))。
請(qǐng)參閱討論有關(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, disablethis listener/subscriber
// Object "this" points to theCometD 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://cometd.org/documentation/cometd/ext可以看到。
通配符訂閱
可以一次使用通配符來(lái)訂閱幾個(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è)自定義安全政策來(lái)改變。
通配符只能被指定在頻道的最后部分,所以這些都是無(wú)效的訂閱:/ ** / 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),在頁(yè)面上顯示一個(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()) // Availablesince 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)證步驟。
在注冊(cè)/meta/handshake頻道情況下,可以返回相關(guān)細(xì)節(jié),例如,驗(yàn)證失敗的細(xì)節(jié)。
聯(lián)系客服