Sottoprotocolo Protobuf WebSocket supportato da WebSocket di Azure
Questo documento descrive il sottoprotocolo protobuf.webpubsub.azure.v1
.
Quando un client usa questo sottoprotocolo, è previsto che i frame di dati in uscita e in ingresso siano payload di buffer di protocollo (protobuf).
Panoramica
Subprotocol protobuf.webpubsub.azure.v1
consente al client di eseguire direttamente una sottoscrizione di pubblicazione (PubSub) anziché eseguire un round trip al server upstream. La connessione WebSocket con il protobuf.webpubsub.azure.v1
sottoprotocolo è denominata client WebSocket PubSocket.
In JavaScript, ad esempio, è possibile creare un client WebSocket PubSub con il sottoprotocolo protobuf usando:
// PubSub WebSocket client
var pubsub = new WebSocket('wss://test.webpubsub.azure.com/client/hubs/hub1', 'protobuf.webpubsub.azure.v1');
Per un semplice client WebSocket, il server ha il ruolo necessario per la gestione degli eventi dai client. Una semplice connessione WebSocket attiva sempre un message
evento quando invia messaggi e si basa sempre sul lato server per elaborare i messaggi ed eseguire altre operazioni. Con l'aiuto del protobuf.webpubsub.azure.v1
sottoprotocolo, un client autorizzato può partecipare a un gruppo usando richieste di join e pubblicare messaggi in un gruppo usando direttamente le richieste di pubblicazione. Il client può anche instradare i messaggi a vari gestori eventi upstream usando richieste di eventi per personalizzare l'evento a cui appartiene il messaggio.
Nota
Attualmente, il servizio Web PubSub supporta solo proto3.
Autorizzazioni
Un client WebSocket PubSocket può pubblicare solo in altri client quando è autorizzato. L'oggetto roles
assegnato al client determina le autorizzazioni concesse al client:
Ruolo | Autorizzazione |
---|---|
Non specificato | Il client può inviare richieste di eventi. |
webpubsub.joinLeaveGroup |
Il client può unirsi o abbandonare qualsiasi gruppo. |
webpubsub.sendToGroup |
Il client può pubblicare messaggi in qualsiasi gruppo. |
webpubsub.joinLeaveGroup.<group> |
Il client può partecipare/lasciare il gruppo <group> . |
webpubsub.sendToGroup.<group> |
Il client può pubblicare messaggi nel gruppo <group> . |
Il server può concedere o revocare in modo dinamico le autorizzazioni client tramite API REST o SDK del server.
Richieste
Tutti i messaggi di richiesta rispettano il seguente formato protobuf:
syntax = "proto3";
import "google/protobuf/any.proto";
message UpstreamMessage {
oneof message {
SendToGroupMessage send_to_group_message = 1;
EventMessage event_message = 5;
JoinGroupMessage join_group_message = 6;
LeaveGroupMessage leave_group_message = 7;
SequenceAckMessage sequence_ack_message = 8;
PingMessage ping_message = 9;
}
message SendToGroupMessage {
string group = 1;
optional uint64 ack_id = 2;
MessageData data = 3;
}
message EventMessage {
string event = 1;
MessageData data = 2;
optional uint64 ack_id = 3;
}
message JoinGroupMessage {
string group = 1;
optional uint64 ack_id = 2;
}
message LeaveGroupMessage {
string group = 1;
optional uint64 ack_id = 2;
}
message PingMessage {
}
}
message MessageData {
oneof data {
string text_data = 1;
bytes binary_data = 2;
google.protobuf.Any protobuf_data = 3;
}
}
Partecipare ai gruppi
Formato:
Impostare join_group_message.group
sul nome del gruppo.
-
ackId
è l'identità di ogni richiesta e deve essere univoca. Il servizio invia un messaggio di risposta ack per notificare il risultato del processo della richiesta. Altri dettagli sono disponibili in AckId e Ack Response
Lasciare i gruppi
Formato:
Impostare leave_group_message.group
sul nome del gruppo.
-
ackId
è l'identità di ogni richiesta e deve essere univoca. Il servizio invia un messaggio di risposta ack per notificare il risultato del processo della richiesta. Altri dettagli sono disponibili in AckId e Ack Response
Pubblicare messaggi
Formato:
ackId
: identità univoca di ogni richiesta. Il servizio invia un messaggio di risposta ack per notificare il risultato del processo della richiesta. Altri dettagli sono disponibili in AckId e Ack ResponsedataType
: formato di dati, che può essereprotobuf
,text
obinary
a seconda didata
inMessageData
. I client riceventi possono usaredataType
per elaborare correttamente il contenuto.protobuf
: quando si impostasend_to_group_message.data.protobuf_data
, l'implicitodataType
èprotobuf
.protobuf_data
può essere di qualsiasi tipo di messaggio. Tutti gli altri client ricevono un file binario con codifica protobuf, che può essere deserializzato dall'SDK protobuf. I client che supportano solo il contenuto basato su testo ,ad esempio ,json.webpubsub.azure.v1
ricevono un file binario con codifica Base64.text
: quando si impostasend_to_group_message.data.text_data
, l'implicitodataType
ètext
.text_data
deve essere una stringa. Tutti i client con altri protocolli ricevono una stringa con codifica UTF-8.binary
: quando si impostasend_to_group_message.data.binary_data
, l'implicitodataType
èbinary
.binary_data
deve essere una matrice di byte. Tutti i client con altri protocolli ricevono un file binario non elaborato senza codifica protobuf. I client che supportano solo il contenuto basato su testo ,ad esempio ,json.webpubsub.azure.v1
ricevono un file binario con codifica Base64.
Caso 1: Pubblicare dati di testo
Impostare send_to_group_message.group
su group
e impostare su send_to_group_message.data.text_data
"text data"
.
Il client subprotocol protobuf in gruppo
group
riceve il frame binario e può usare DownstreamMessage per deserializzarlo.I client del sottoprotocolo JSON in
group
ricevono:{ "type": "message", "from": "group", "group": "group", "dataType" : "text", "data" : "text data" }
I semplici client WebSocket nella
group
stringatext data
di ricezione.
Caso 2: Pubblicare dati protobuf
Si supponga di avere un messaggio personalizzato:
message MyMessage {
int32 value = 1;
}
Impostare su send_to_group_message.group
group
e send_to_group_message.data.protobuf_data
su Any.pack(MyMessage)
con value = 1
.
I client protobuf subprotocol in
group
ricevono il frame binario e possono usare DownstreamMessage per deserializzarlo.Il client subprotocol in
group
riceve:{ "type": "message", "from": "group", "group": "G", "dataType" : "protobuf", "data" : "Ci90eXBlLmdvb2dsZWFwaXMuY29tL2F6dXJlLndlYnB1YnN1Yi5UZXN0TWVzc2FnZRICCAE=" // Base64-encoded bytes }
Nota
I dati sono un file binario protobuf con codifica Base64 deserializeable.
È possibile usare la definizione protobuf seguente e usarla Any.unpack()
per deserializzarla:
syntax = "proto3";
message MyMessage {
int32 value = 1;
}
I semplici client WebSocket in
group
ricevono il frame binario:# Show in hexadecimal 0A 2F 74 79 70 65 2E 67 6F 6F 67 6C 65 61 70 69 73 2E 63 6F 6D 2F 61 7A 75 72 65 2E 77 65 62 70 75 62 73 75 62 2E 54 65 73 74 4D 65 73 73 61 67 65 12 02 08 01
Caso 3: Pubblicare dati binari
Impostare send_to_group_message.group
su group
e impostare su send_to_group_message.data.binary_data
[1, 2, 3]
.
Il client subprotocol protobuf in gruppo
group
riceve il frame binario e può usare DownstreamMessage per deserializzarlo.Il client del sottoprotocolo JSON in gruppo
group
riceve:{ "type": "message", "from": "group", "group": "group", "dataType" : "binary", "data" : "AQID", // Base64-encoded [1,2,3] }
Poiché il client di sottoprotocolo JSON supporta solo la messaggistica basata su testo, il file binario è sempre con codifica Base64.
I semplici client WebSocket in
group
ricevono i dati binari nel frame binario:# Show in hexadecimal 01 02 03
Inviare eventi personalizzati
È presente un oggetto implicito dataType
, che può essere protobuf
, text
o binary
, a seconda dell'oggetto dataType
impostato. I client ricevitori possono usare dataType
per gestire correttamente il contenuto.
protobuf
: quando si impostaevent_message.data.protobuf_data
, l'implicitodataType
èprotobuf
. Ilprotobuf_data
valore può essere qualsiasi tipo protobuf supportato. Il gestore eventi riceve il file binario con codifica protobuf, che può essere deserializzato da qualsiasi SDK protobuf.text
: quando si impostaevent_message.data.text_data
, l'implicitodataType
ètext
. Iltext_data
valore deve essere una stringa. Il gestore eventi riceve una stringa con codifica UTF-8.binary
: quando si impostaevent_message.data.binary_data
, l'implicitodataType
èbinary
. Ilbinary_data
valore deve essere una matrice di byte. Il gestore eventi riceve il frame binario non elaborato.
Caso 1: Inviare un evento con dati di testo
Impostare event_message.data.text_data
su "text data"
.
Il gestore eventi upstream riceve una richiesta simile a:
POST /upstream HTTP/1.1
Host: xxxxxx
WebHook-Request-Origin: xxx.webpubsub.azure.com
Content-Type: text/plain
Content-Length: nnnn
ce-specversion: 1.0
ce-type: azure.webpubsub.user.<event_name>
ce-source: /client/{connectionId}
ce-id: {eventId}
ce-time: 2021-01-01T00:00:00Z
ce-signature: sha256={connection-id-hash-primary},sha256={connection-id-hash-secondary}
ce-userId: {userId}
ce-connectionId: {connectionId}
ce-hub: {hub_name}
ce-eventName: <event_name>
text data
Per Content-Type
la richiesta HTTP CloudEvents è text/plain
, dove=dataType
text
.
Caso 2: Inviare un evento con dati protobuf
Si supponga di aver ricevuto il seguente messaggio del cliente:
message MyMessage {
int32 value = 1;
}
Impostare event_message.data.protobuf_data
su any.pack(MyMessage)
con value = 1
Il gestore eventi upstream riceve una richiesta simile a:
POST /upstream HTTP/1.1
Host: xxxxxx
WebHook-Request-Origin: xxx.webpubsub.azure.com
Content-Type: application/json
Content-Length: nnnn
ce-specversion: 1.0
ce-type: azure.webpubsub.user.<event_name>
ce-source: /client/{connectionId}
ce-id: {eventId}
ce-time: 2021-01-01T00:00:00Z
ce-signature: sha256={connection-id-hash-primary},sha256={connection-id-hash-secondary}
ce-userId: {userId}
ce-connectionId: {connectionId}
ce-hub: {hub_name}
ce-eventName: <event_name>
// Just show in hexadecimal; read it as binary
0A 2F 74 79 70 65 2E 67 6F 6F 67 6C 65 61 70 69 73 2E 63 6F 6D 2F 61 7A 75 72 65 2E 77 65 62 70 75 62 73 75 62 2E 54 65 73 74 4D 65 73 73 61 67 65 12 02 08 01
Per Content-Type
la richiesta HTTP CloudEvents è application/x-protobuf
, dove=dataType
protobuf
.
I dati sono un file binario protobuf valido. È possibile usare quanto segue proto
e any.unpack()
per deserializzarlo:
syntax = "proto3";
message MyMessage {
int32 value = 1;
}
Caso 3: Inviare un evento con dati binari
Impostare send_to_group_message.binary_data
su [1, 2, 3]
.
Il gestore eventi upstream riceve una richiesta simile a:
POST /upstream HTTP/1.1
Host: xxxxxx
WebHook-Request-Origin: xxx.webpubsub.azure.com
Content-Type: application/octet-stream
Content-Length: nnnn
ce-specversion: 1.0
ce-type: azure.webpubsub.user.<event_name>
ce-source: /client/{connectionId}
ce-id: {eventId}
ce-time: 2021-01-01T00:00:00Z
ce-signature: sha256={connection-id-hash-primary},sha256={connection-id-hash-secondary}
ce-userId: {userId}
ce-connectionId: {connectionId}
ce-hub: {hub_name}
ce-eventName: <event_name>
// Just show in hexadecimal; you need to read it as binary
01 02 03
Per dataType
=binary
, per Content-Type
la richiesta HTTP CloudEvents è application/octet-stream
. Il frame WebSocket può essere in text
formato per frame di messaggi di testo o file binari con codifica UTF-8 per binary
i fotogrammi di messaggio.
Il servizio rifiuta il client se il messaggio non corrisponde al formato specificato.
Ping
Il client può inviare un oggetto PingMessage
al servizio per consentire al servizio Web PubSub di rilevare la durata del client.
Risposte
Tutti i messaggi di risposta rispettano il seguente formato protobuf:
message DownstreamMessage {
oneof message {
AckMessage ack_message = 1;
DataMessage data_message = 2;
SystemMessage system_message = 3;
PongMessage pong_message = 4;
}
message AckMessage {
uint64 ack_id = 1;
bool success = 2;
optional ErrorMessage error = 3;
message ErrorMessage {
string name = 1;
string message = 2;
}
}
message DataMessage {
string from = 1;
optional string group = 2;
MessageData data = 3;
}
message SystemMessage {
oneof message {
ConnectedMessage connected_message = 1;
DisconnectedMessage disconnected_message = 2;
}
message ConnectedMessage {
string connection_id = 1;
string user_id = 2;
}
message DisconnectedMessage {
string reason = 2;
}
}
message PongMessage {
}
}
I messaggi ricevuti dal client possono trovarsi in uno dei tre tipi seguenti: ack
, message
system
o pong
.
Risposta Ack
Se la richiesta contiene ackId
, il servizio restituisce una risposta ack per questa richiesta. L'implementazione client deve gestire questo meccanismo ack, tra cui:
- In attesa della risposta ack per un'operazione
async
await
. - Verifica del timeout quando la risposta ack non viene ricevuta durante un determinato periodo.
L'implementazione del client deve sempre controllare prima di tutto se lo success
stato è true
o false
. Quando lo success
stato è false
, il client può leggere dalla proprietà per i dettagli dell'errore error
.
Risposta al messaggio
I client possono ricevere messaggi pubblicati da un gruppo aggiunto al client. Oppure possono ricevere messaggi dal ruolo di gestione del server quando il server invia messaggi a un client specifico o a un utente specifico.
Verrà sempre visualizzato un DownstreamMessage.DataMessage
messaggio negli scenari seguenti:
- Quando il messaggio proviene da un gruppo,
from
ègroup
. Quando il messaggio proviene dal server,from
èserver
. - Quando il messaggio proviene da un gruppo,
group
è il nome del gruppo.
Il mittente causerà l'invio dataType
di uno dei messaggi seguenti:
- Se
dataType
ètext
, usaremessage_response_message.data.text_data
. - Se
dataType
èbinary
, usaremessage_response_message.data.binary_data
. - Se
dataType
èprotobuf
, usaremessage_response_message.data.protobuf_data
. - Se
dataType
èjson
, usaremessage_response_message.data.text_data
e il contenuto è una stringa JSON serializzata.
Risposta di sistema
Il servizio Web PubSub può anche inviare risposte correlate al sistema al client.
Connesso
Quando il client si connette al servizio, viene visualizzato un DownstreamMessage.SystemMessage.ConnectedMessage
messaggio.
Disconnesso
Quando il server chiude la connessione o il servizio rifiuta il client, viene visualizzato un DownstreamMessage.SystemMessage.DisconnectedMessage
messaggio.
Risposta pong
Il servizio Web PubSub invia un oggetto PongMessage
al client quando riceve un PingMessage
oggetto dal client.
Passaggi successivi
Usare queste risorse per iniziare a compilare un'applicazione personalizzata: