Sottoprotocolo JSON WebSocket supportato da Web PubSub di Azure

Il sottoprotocolo JSON WebSocket, json.webpubsub.azure.v1, consente lo scambio di messaggi di pubblicazione/sottoscrizione tra i client tramite il servizio senza un round trip al server upstream. Una connessione WebSocket che usa il json.webpubsub.azure.v1 sottoprotocolo viene chiamata client WebSocket PubSub.

Panoramica

Una semplice connessione WebSocket attiva un message evento quando invia messaggi e si basa sul lato server per elaborare i messaggi ed eseguire altre operazioni.

Con il json.webpubsub.azure.v1 sottoprotocolo è possibile creare client PubSub WebSocket che possono:

Ad esempio, è possibile creare un client WebSocket PubSocket con il codice JavaScript seguente:

// PubSub WebSocket client
var pubsub = new WebSocket('wss://test.webpubsub.azure.com/client/hubs/hub1', 'json.webpubsub.azure.v1');

Questo documento descrive le richieste e le risposte del sottoprotocolo json.webpubsub.azure.v1 . Sia i frame di dati in ingresso che in uscita devono contenere payload JSON.

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>.
webpubsub.joinLeaveGroups.<pattern> Il client può partecipare/lasciare qualsiasi gruppo il cui nome corrisponde <pattern> (vedere Modelli di ruolo del gruppo con caratteri jolly).
webpubsub.sendToGroups.<pattern> Il client può pubblicare messaggi in qualsiasi gruppo i cui nomi corrispondono <pattern> (vedere Modelli di ruolo del gruppo con caratteri jolly).

Il server può concedere o revocare in modo dinamico le autorizzazioni client tramite API REST o SDK del server.

Annotazioni

I ruoli con caratteri jolly (ad esempio , webpubsub.sendToGroups.<pattern>) non sono ancora supportati nelle API REST o negli SDK del server durante il runtime.

Richieste

Partecipare ai gruppi

Formato:

{
    "type": "joinGroup",
    "group": "<group_name>",
    "ackId" : 1
}
  • 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. Per informazioni dettagliate, vedere AckId e Risposta Ack

Lasciare i gruppi

Formato:

{
    "type": "leaveGroup",
    "group": "<group_name>",
    "ackId" : 1
}
  • 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. Per informazioni dettagliate, vedere AckId e Risposta Ack

Pubblicare messaggi

Formato:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "ackId" : 1,
    "noEcho": true|false,
    "dataType" : "json|text|binary",
    "data": {}, // data can be string or valid json token depending on the dataType 
}
  • 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. Per informazioni dettagliate, vedere AckId e Risposta Ack
  • noEcho è facoltativo. Se impostato su true, questo messaggio non viene restituito alla stessa connessione. Se non è impostato, il valore predefinito è false.
  • dataType può essere impostato su json, texto binary:
    • json: data può essere qualsiasi tipo supportato da JSON e verrà pubblicato come quello che è; Se dataType non viene specificato, per impostazione predefinita è json.
    • text: data deve essere in formato stringa e i dati stringa verranno pubblicati;
    • binary: data deve essere in formato base64 e i dati binari verranno pubblicati;

Caso 1: pubblicare dati di testo:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "dataType" : "text",
    "data": "text data",
    "ackId": 1
}
  • I client subprotocol in <group_name> ricevono:
{
    "type": "message",
    "from": "group",
    "group": "<group_name>",
    "dataType" : "text",
    "data" : "text data"
}
  • I semplici client WebSocket in <group_name> ricevono la stringa text data.

Caso 2: pubblicare dati JSON:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "dataType" : "json",
    "data": {
        "hello": "world"
    }
}
  • I client subprotocol in <group_name> ricevono:
{
    "type": "message",
    "from": "group",
    "group": "<group_name>",
    "dataType" : "json",
    "data" : {
        "hello": "world"
    }
}
  • I semplici client WebSocket in <group_name> ricevono la stringa {"hello": "world"}serializzata .

Caso 3: pubblicare dati binari:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "dataType" : "binary",
    "data": "<base64_binary>",
    "ackId": 1
}
  • I client subprotocol in <group_name> ricevono:
{
    "type": "message",
    "from": "group",
    "group": "<group_name>",
    "dataType" : "binary",
    "data" : "<base64_binary>", 
}
  • I semplici client WebSocket in <group_name> ricevono i dati binari nel frame binario.

Inizia a trasmettere messaggi

Per avviare un stream di gruppo, invia una sendToGroup richiesta alla stream proprietà. Una richiesta di avvio di flusso non contiene data, dataType, o ackId.

Formato:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "noEcho": true|false,
    "stream": {
        "streamId": "<stream_id>",
        "idleTimeoutMs": 300000
    }
}
  • stream.streamId è l'identificatore del flusso logico. Deve essere una stringa non vuota e deve essere unica tra i flussi attivi sulla stessa connessione client. Si consiglia alle librerie client di generare un valore globalmente unico, come un GUID o un UUID.
  • stream.idleTimeoutMs è facoltativo. Se specificato, deve essere maggiore di 0. Se omesso, il valore predefinito del servizio è 300000 millisecondo. Il valore è un timeout inattivo, non una durata totale del flusso di streaming. Invia dati del stream, invia un keep live, oppure termina lo stream prima che scada questo timeout, quando l'applicazione deve mantenere lo stream aperto.
  • noEcho è facoltativo. Se impostato su true, i messaggi di stream non vengono richiamati alla stessa connessione. Se non è impostato, il valore predefinito è false.

Quando lo stream viene accettato, il client riceve una risposta di ack dello stream impostata expectedSequenceId a 1.

Invia dati in streaming

Per inviare dati di flusso, invia una streamData richiesta con streamId, streamSequenceId, dataType, e data.

Formato:

{
    "type": "streamData",
    "streamId": "<stream_id>",
    "streamSequenceId": 1,
    "dataType" : "json|text|binary",
    "data": {}
}
  • streamId identifica un flusso attivo sulla stessa connessione client.
  • streamSequenceId è un numero uint64 positivo. Il primo frammento di dati in un flusso usa 1, e ogni frammento di dato successivo per lo stesso streamId aumenta esattamente 1di .
  • dataType può essere impostato su json, text, o binary, con le stesse regole di codifica dei dati di pubblicazione dei messaggi.

Per mantenere un flusso attivo senza fornire dati agli abbonati, invia una streamData richiesta con solo type e streamId.

{
    "type": "streamData",
    "streamId": "<stream_id>"
}

Fine dei messaggi in streaming

Per terminare una diretta, invia una streamEnd richiesta.

Formato:

{
    "type": "streamEnd",
    "streamId": "<stream_id>"
}

Per concludere uno stream con un errore definito dall'applicazione, includere la proprietà opzionale error .

{
    "type": "streamEnd",
    "streamId": "<stream_id>",
    "error": {
        "message": "<error_detail>",
        "userErrorCode": "<application_error_code>"
    }
}
  • error.message è un messaggio di errore opzionale leggibile dagli umani.
  • error.userErrorCode è un codice di errore opzionale definito dall'applicazione.

Quando lo stream è chiuso, l'editore riceve una risposta di stream closed.

Inviare eventi personalizzati

Formato:

{
    "type": "event",
    "event": "<event_name>",
    "ackId": 1,
    "dataType" : "json|text|binary",
    "data": {}, // data can be string or valid json token depending on the dataType 
}
  • 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. Per informazioni dettagliate, vedere AckId e Risposta Ack

dataType può essere uno di text, binaryo json:

  • json: i dati possono essere supportati da qualsiasi tipo json e verranno pubblicati come sono; Il valore predefinito è json.
  • text: i dati sono in formato stringa e i dati stringa verranno pubblicati;
  • binary: i dati sono in formato base64 e i dati binari verranno pubblicati;

Caso 1: inviare un evento con dati di testo:

{
    "type": "event",
    "event": "<event_name>",
    "ackId": 1,
    "dataType" : "text",
    "data": "text data", 
}

Il gestore eventi upstream riceve dati simili 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 quando dataType è text.

Caso 2: inviare un evento con dati JSON:

{
    "type": "event",
    "event": "<event_name>",
    "ackId": 1,
    "dataType" : "json",
    "data": {
        "hello": "world"
    }, 
}

Il gestore eventi upstream riceve dati simili 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>

{
    "hello": "world"
}

L'oggetto Content-Type per la richiesta HTTP CloudEvents è application/json quando dataType è json

Caso 3: inviare un evento con dati binari:

{
    "type": "event",
    "event": "<event_name>",
    "ackId": 1,
    "dataType" : "binary",
    "data": "base64_binary", 
}

Il gestore eventi upstream riceve dati simili 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>

binary

Per Content-Type la richiesta HTTP CloudEvents è application/octet-stream quando dataType è binary. Il frame WebSocket può essere text formattato per frame di testo o file binari con codifica UTF8 per binary i fotogrammi di messaggio.

Il servizio Web PubSub rifiuta il client se il messaggio non corrisponde al formato descritto.

Ping

Formato:

{
    "type": "ping",
}

Il client può inviare un ping messaggio al servizio per consentire al servizio Web PubSub di rilevare la durata del client.

Risposte

I tipi di messaggio ricevuti dal client possono essere:

  • ack: risposta a una richiesta contenente un oggetto ackId.
  • message: messaggi provenienti dal gruppo o dal server.
  • system: messaggi dal servizio Web PubSub.
  • pong - La risposta a un ping messaggio.
  • streamAck - La risposta che riconosce i dati del flusso accettati e riporta il prossimo ID atteso della sequenza del flusso.
  • streamNack - La risposta a un errore di flusso ritentabile.
  • streamClosed - La risposta alla chiusura del flusso lato publisher del terminale.

Risposta Ack

Quando la richiesta client contiene ackId, il servizio restituirà una risposta ack per la richiesta. Il client deve gestire il meccanismo ack, attendendo la risposta ack con un'operazione asyncawait e usando un'operazione di timeout quando la risposta ack non viene ricevuta in un determinato periodo.

Formato:

{
    "type": "ack",
    "ackId": 1, // The ack id for the request to ack
    "success": false, // true or false
    "error": {
        "name": "Forbidden|InternalServerError|Duplicate",
        "message": "<error_detail>"
    }
}

L'implementazione del client DEVE sempre controllare se success è true o false prima, quindi leggere solo l'errore quando success è false.

Risposta al messaggio

I client possono ricevere messaggi pubblicati da un gruppo che il client ha aggiunto o dal server, che opera in un ruolo di gestione del server, invia messaggi a client o utenti specifici.

  1. Quando il messaggio proviene da un gruppo

    {
        "type": "message",
        "from": "group",
        "group": "<group_name>",
        "dataType": "json|text|binary",
        "data" : {} // The data format is based on the dataType
        "fromUserId": "abc"
    }
    
  2. Quando il messaggio proviene dal server.

    {
        "type": "message",
        "from": "server",
        "dataType": "json|text|binary",
        "data" : {} // The data format is based on the dataType
    }
    

Caso 1: Invio di dati Hello World alla connessione tramite l'API REST con Content-Type=text/plain

  • Un semplice client WebSocket riceve un frame WebSocket di testo con dati: Hello World;

  • Un client PubSub WebSocket riceve:

    {
        "type": "message",
        "from": "server",
        "dataType" : "text",
        "data": "Hello World", 
    }
    

Caso 2: Invio di dati { "Hello" : "World"} alla connessione tramite l'API REST con Content-Type=application/json

  • Un semplice client WebSocket riceve un frame WebSocket di testo con dati stringati: { "Hello" : "World"}.

  • Un client PubSub WebSocket riceve:

    {
        "type": "message",
        "from": "server",
        "dataType" : "json",
        "data": {
            "Hello": "World"
        }
    }
    

Se l'API REST invia una stringa Hello World usando application/json il tipo di contenuto, il client WebSocket semplice riceve una stringa JSON, di cui viene "Hello World" eseguito il wrapping con virgolette doppie (").

Caso 3: Invio di dati binari alla connessione tramite l'API REST con Content-Type=application/octet-stream

  • Un semplice client WebSocket riceve un frame WebSocket binario con i dati binari.

  • Un client PubSub WebSocket riceve:

    {
        "type": "message",
        "from": "server",
        "dataType" : "binary",
        "data": "<base64_binary>"
    }
    

Risposta al messaggio in streaming

Quando un messaggio appartiene a un stream, il messaggio di gruppo contiene una stream proprietà.

{
    "type": "message",
    "from": "group",
    "group": "<group_name>",
    "dataType": "json|text|binary",
    "data": {},
    "fromUserId": "abc",
    "stream": {
        "streamId": "<stream_id>",
        "streamSequenceId": 1,
        "endOfStream": true,
        "error": {
            "name": "IdleTimeout|InternalServerError|Forbidden|Cancelled|UserError",
            "message": "<error_detail>",
            "userErrorCode": "<application_error_code>"
        }
    }
}
  • stream.streamId è l'identificatore logico del flusso.
  • stream.streamSequenceId è il numero di sequenza del messaggio nel flusso.
  • stream.endOfStream è facoltativo. Quando impostato su true, il messaggio è il messaggio terminale del flusso.
  • stream.error è opzionale ed è presente solo quando il flusso termina con un errore. userErrorCode è presente solo per UserError.

Risposta al flusso

Il servizio invia una streamAck risposta per confermare i dati di flusso accettati e per segnalare il prossimo ID della sequenza di flusso che si aspetta.

Formato:

{
    "type": "streamAck",
    "streamId": "<stream_id>",
    "expectedSequenceId": 2
}

Risposta al nack del corso d'acqua

Il servizio invia una streamNack risposta per un errore di flusso ritentabile.

Formato:

{
    "type": "streamNack",
    "streamId": "<stream_id>",
    "expectedSequenceId": 2,
    "name": "InvalidSequenceId|TransientError",
    "message": "<error_detail>"
}

Risposta chiusa del flusso

Il servizio invia una streamClosed risposta quando lo stream lato publisher viene chiuso.

Formato:

{
    "type": "streamClosed",
    "streamId": "<stream_id>",
    "error": {
        "name": "StreamNotFound|Forbidden|BadRequest|InternalServerError|IdleTimeout",
        "message": "<error_detail>"
    }
}

La error proprietà viene omessa quando il flusso è chiuso normalmente.

Risposta di sistema

Il servizio Web PubSub invia messaggi correlati al sistema ai client.

Risposta pong

Il servizio Web PubSub invia un pong messaggio al client quando riceve un ping messaggio dal client.

Formato:

{
    "type": "pong",
}

Connesso

Messaggio inviato al client quando il client si connette correttamente:

{
    "type": "system",
    "event": "connected",
    "userId": "user1",
    "connectionId": "abcdefghijklmnop",
}

Disconnesso

Messaggio inviato al client quando il server chiude la connessione o quando il servizio rifiuta il client.

{
    "type": "system",
    "event": "disconnected",
    "message": "reason"
}

Passaggi successivi

Usare queste risorse per iniziare a compilare un'applicazione personalizzata: