使用 subprotocol 建立可靠的 Websocket
當 Websocket 用戶端連線因為間歇性網路問題而中斷時,訊息可能會遺失。 在發行/訂閱系統中,發行者會與訂閱者分離,因此發行者可能不會偵測到訂閱者的中斷連線或訊息遺失。 用戶端必須克服間歇性網路問題並維護可靠的訊息傳遞。 若要達成此目的,您可以使用可靠的 Azure Web PubSub 子程式來建立可靠的 Websocket 用戶端。
可靠的通訊協定
Web PubSub 服務支援兩個可靠的子專案 json.reliable.webpubsub.azure.v1
和 protobuf.reliable.webpubsub.azure.v1
。 客戶端必須遵循子協議的發行者、訂閱者和復原部分,才能達到可靠性。 無法正確實作子程式可能會導致訊息傳遞無法如預期般運作,或因通訊協定違規而終止客戶端的服務。
簡單方式 - 使用用戶端 SDK
建立可靠客戶端最簡單的方式是使用用戶端 SDK。 用戶端 SDK 會實作 Web PubSub 用戶端規格 ,並預設使用 json.reliable.webpubsub.azure.v1
。 如需快速入門, 請參閱用戶端 之間的發佈/訂閱。
硬式方法 - 手動實作
下列教學課程將逐步引導您完成實 作 Web PubSub 用戶端規格的重要部分。 本指南不適用於想要快速啟動但想要了解達成可靠性原則的人員。 如需快速入門,請使用用戶端 SDK。
初始化
若要使用可靠的子程式,您必須在建構 Websocket 連線時設定子程式。 在 JavaScript 中,您可以使用下列程式代碼:
使用 Json 可靠子程式:
var pubsub = new WebSocket( "wss://test.webpubsub.azure.com/client/hubs/hub1", "json.reliable.webpubsub.azure.v1" );
使用 Protobuf 可靠的子程式:
var pubsub = new WebSocket( "wss://test.webpubsub.azure.com/client/hubs/hub1", "protobuf.reliable.webpubsub.azure.v1" );
連線復原
連線 復原是達到可靠性的基礎,而且在使用 和 protobuf.reliable.webpubsub.azure.v1
通訊協議時必須實作json.reliable.webpubsub.azure.v1
。
Websocket 連線依賴 TCP。 當連線未卸除時,訊息會遺失並依序傳遞。 為了防止訊息中斷連線,Web PubSub 服務會保留連線狀態資訊,包括群組和訊息資訊。 此資訊可用來還原聯機復原上的用戶端
當用戶端使用可靠的子程式重新連線至服務時,用戶端會收到包含 Connected
和reconnectionToken
的connectionId
訊息。 會 connectionId
識別服務中聯機的會話。
{
"type": "system",
"event": "connected",
"connectionId": "<connection_id>",
"reconnectionToken": "<reconnection_token>"
}
一旦 WebSocket 連線中斷,客戶端應該嘗試使用相同的 connectionId
重新連線,以還原相同的會話。 用戶端不需要與伺服器交涉並取得 access_token
。 相反地,若要復原連線,客戶端應該使用服務主機名、 connection_id
和 reconnection_token
直接對服務提出 WebSocket 連線要求:
wss://<service-endpoint>/client/hubs/<hub>?awps_connection_id=<connection_id>&awps_reconnection_token=<reconnection_token>
如果尚未復原網路問題,連線 復原可能會失敗。 用戶端應該持續重試以重新連線,直到:
- Websocket 連線已關閉,狀態代碼為1008。 狀態代碼表示 connectionId 已從服務中移除。
- 復原失敗會持續超過 1 分鐘。
發行者
將事件傳送至事件處理程式或將訊息發佈至其他用戶端的用戶端稱為「發行者」。 發行者應該在訊息中設定 ackId
為接收來自發佈訊息成功的 Web PubSub 服務的認可。
ackId
是訊息的標識碼,每個新訊息都應該使用唯一標識符。 重新傳送訊息時,應該使用原始 ackId
的 。
範例群組傳送訊息:
{
"type": "sendToGroup",
"group": "group1",
"dataType": "text",
"data": "text data",
"ackId": 1
}
範例 ack 回應:
{
"type": "ack",
"ackId": 1,
"success": true
}
當 Web PubSub 服務傳回的 ack 回應時 success: true
,服務已處理訊息,而且用戶端可以預期訊息會傳遞至所有訂閱者。
當服務發生暫時性內部錯誤且訊息無法傳送至訂閱者時,發行者會收到具有 success: false
的 ack。 發行者應該讀取錯誤,以判斷是否要重新傳送訊息。 如果訊息已重新傳送, ackId
則應該使用相同的訊息。
{
"type": "ack",
"ackId": 1,
"success": false,
"error": {
"name": "InternalServerError",
"message": "Internal server error"
}
}
如果服務的 ack 回應因為 WebSocket 連線中斷而遺失,發行者應該在復原之後以相同的 ackId
方式重新傳送訊息。 服務先前處理訊息時,會傳送包含 Duplicate
錯誤的ack。 發行者應該停止重新傳送此訊息。
{
"type": "ack",
"ackId": 1,
"success": false,
"error": {
"name": "Duplicate",
"message": "Message with ack-id: 1 has been processed"
}
}
訂閱者
從事件處理程式或發行者接收訊息的用戶端稱為訂閱者。 當連線因為網路問題而中斷時,Web PubSub 服務並不知道有多少訊息已傳送給訂閱者。 若要判斷訂閱者收到的最後一則訊息,服務會傳送包含 sequenceId
的數據訊息。 訂閱者會以序列 ack 訊息回應:
範例序列ack:
{
"type": "sequenceAck",
"sequenceId": 1
}
sequenceId
是聯機標識符會話中的 uint64 累加數位。 訂閱者應該記錄它已接收的最大 sequenceId
數目、只接受具有較大 sequenceId
、且卸除較小或等於 sequenceId
的訊息。 訂閱者應該使用記錄的最大 sequenceId
訂閱者來攔截,以便服務可以略過訂閱者已接收的重新傳遞訊息。 例如,如果訂閱者以 sequenceAck
sequenceId: 5
回應 ,則服務只會重新傳送大於5的 sequenceId
訊息。
所有訊息都會依序傳遞至訂閱者,直到 WebSocket 連線中斷為止。 透過 sequenceId
,服務可以知道會話中 WebSocket 連線已接收多少個訊息訂閱者。 WebSocket 連線卸除之後,服務將會重新傳遞訂閱者未認可的訊息。 服務會儲存有限的未認可訊息數目。 當訊息數目超過限制時,服務將會關閉 WebSocket 連線並移除會話。 因此,訂閱者應該儘快予以解僱 sequenceId
。