Subprotocolo de WebSocket JSON de confianza con Azure Web PubSub

El subprotocolo de WebSocket JSON, json.reliable.webpubsub.azure.v1, permite el intercambio muy fiable de mensajes de publicación y suscripción directamente entre los clientes a través del servicio sin un recorrido de ida y vuelta al servidor ascendente.

En este documento se describe el subprotocolo json.reliable.webpubsub.azure.v1.

Cuando las conexiones de cliente WebSocket se retiran debido a problemas de red intermitentes, se pueden perder mensajes. En un sistema de tipo publicador/suscriptor, los publicadores se desacoplan de los suscriptores y es posible que no detecten la pérdida de mensajes o la conexión eliminada de los suscriptores.

Para solucionar problemas intermitentes de red y mantener una entrega de mensajes fiable, puede usar el subprotocolo de Azure WebPubSub json.reliable.webpubsub.azure.v1 para crear un Cliente WebSocket de PubSub de confianza.

Un Cliente WebSocket de PubSub de confianza puede:

Por ejemplo, puede crear un Cliente WebSocket de PubSub de confianza con el código de JavaScript siguiente:

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

Consulte Creación de clientes de confianza para implementar la reconexión y la fiabilidad de mensajes para clientes de publicador y suscriptor.

Cuando el cliente usa este subprotocolo, los marcos de datos salientes y entrantes deben contener cargas JSON.

Permisos

Un cliente de WebSocket de PubSub solo puede publicar en otros clientes cuando está autorizado. El roles asignado al cliente determina los permisos concedidos al cliente:

Role Permiso
No especificado El cliente puede enviar solicitudes de eventos.
webpubsub.joinLeaveGroup El cliente puede unirse a cualquier grupo o abandonarlo.
webpubsub.sendToGroup El cliente puede publicar mensajes en cualquier grupo.
webpubsub.joinLeaveGroup.<group> El cliente puede unirse al grupo <group> o abandonarlo.
webpubsub.sendToGroup.<group> El cliente puede publicar mensajes en el grupo <group>.
webpubsub.joinLeaveGroups.<pattern> El cliente puede unirse o dejar cualquier grupo cuyo nombre coincida <pattern> (consulte Patrones de rol de grupo comodín).
webpubsub.sendToGroups.<pattern> El cliente puede publicar mensajes en cualquier grupo cuyo nombre coincida <pattern> (consulte Patrones de rol de grupo comodín).

El servidor puede conceder o revocar los permisos de un cliente de forma dinámica por medio de API REST o SDK de servidor.

Nota:

Los roles comodín (por ejemplo, webpubsub.sendToGroups.<pattern>) no se admiten en las API REST ni en los SDK de servidor durante el tiempo de ejecución.

Requests

Unión a grupos

Formato:

{
    "type": "joinGroup",
    "group": "<group_name>",
    "ackId" : 1
}

Salida de grupos

Formato:

{
    "type": "leaveGroup",
    "group": "<group_name>",
    "ackId" : 1
}

Publicar mensajes

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 es la identidad de cada solicitud y debe ser única. El servicio envía un mensaje de respuesta de confirmación para notificar el resultado del proceso de la solicitud. Para obtener más información, consulte Id. de confirmación y respuesta de confirmación
  • noEcho es opcional. Si se establece en true, este mensaje no se repite en la misma conexión. Si no se establece, el valor predeterminado es false.
  • Se puede establecer en dataType, json, text o binary:
    • json: data puede ser cualquier tipo que JSON admita y se publicará como lo que sea. Si dataType no se especifica, el valor predeterminado es json.
    • text: data debe estar en formato de cadena y se publicarán los datos de cadena.
    • binary: data debe estar en formato base64 y se publicarán los datos binarios.

Caso 1: publicar datos de texto:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "dataType" : "text",
    "data": "text data",
    "ackId": 1
}
  • Los clientes del subprotocolo en <group_name> reciben:
{
    "type": "message",
    "from": "group",
    "group": "<group_name>",
    "dataType" : "text",
    "data" : "text data"
}
  • Los clientes de WebSocket simple en <group_name> reciben la cadena text data.

Caso 2: publicar datos JSON:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "dataType" : "json",
    "data": {
        "hello": "world"
    }
}
  • Los clientes del subprotocolo en <group_name> reciben:
{
    "type": "message",
    "from": "group",
    "group": "<group_name>",
    "dataType" : "json",
    "data" : {
        "hello": "world"
    }
}
  • Los clientes de WebSocket simple en <group_name> reciben la cadena serializada {"hello": "world"}.

Caso 3: publicar datos binarios:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "dataType" : "binary",
    "data": "<base64_binary>",
    "ackId": 1
}
  • Los clientes del subprotocolo en <group_name> reciben:
{
    "type": "message",
    "from": "group",
    "group": "<group_name>",
    "dataType" : "binary",
    "data" : "<base64_binary>", 
}
  • Los clientes de WebSocket simple en <group_name> reciben los datos binarios en el marco binario.

Envío de eventos personalizados

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 
}

dataType puede ser de tipo text, binary o json:

  • json: los datos pueden ser cualquier tipo que JSON admita y se publicará como lo que sea. El valor predeterminado es json.
  • text: los datos están en formato de cadena y se publicarán los datos de cadena;
  • binary: los datos están en formato base64 y se publicarán los datos binarios;

Caso 1: envío de eventos con datos de texto:

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

El controlador de eventos ascendente recibe datos similares 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

El valor Content-Type de la solicitud HTTP de CloudEvents es text/plain, donde dataType es text.

Caso 2: envío de eventos con datos JSON:

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

El controlador de eventos ascendente recibe datos similares 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"
}

El valor Content-Type de la solicitud HTTP de CloudEvents es application/json, donde dataType es json

Caso 3: envío de eventos con datos binarios:

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

El controlador de eventos ascendente recibe datos similares 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

El valor Content-Type de la solicitud HTTP de CloudEvents es application/octet-stream, donde dataType es binary. El marco de WebSocket puede tener formato text para marcos de mensajes de texto o binarios con codificación UTF8 para marcos de mensaje binary.

El servicio Web PubSub rechaza al cliente si el mensaje no coincide con el formato descrito.

Ping

Formato:

{
    "type": "ping",
}

El cliente puede enviar un mensaje ping al servicio para permitir que el servicio Web PubSub detecte el estado de actividad del cliente.

Confirmación de secuencia

Formato:

{
    "type": "sequenceAck",
    "sequenceId": "<sequenceId>",
}

El cliente WebSocket de PubSub de confianza debe enviar un mensaje de confirmación de secuencia cuando recibe un mensaje del servicio. Para más información, consulta Cómo crear clientes de confianza

  • sequenceId es un número incremental uint64 del mensaje recibido.

Respuestas

Los mensajes recibidos por el cliente pueden ser de varios tipos: ack, message, system y pong. Los mensajes con tipo message tienen la propiedad sequenceId. El cliente debe enviar una Confirmación de secuencia al servicio cuando reciba un mensaje.

Respuesta de confirmación

Si la solicitud contiene ackId, el servicio devolverá una respuesta rápida para esta solicitud. La implementación del cliente debe controlar este mecanismo de confirmación, incluida la espera de la respuesta de confirmación mediante una operación asyncawait y disponer de un controlador de tiempo de espera cuando no se recibe la respuesta de confirmación durante un período determinado.

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>"
    }
}

La implementación del cliente siempre DEBE comprobar en primer lugar si success es true o false. Solo cuando success es false, el cliente lee desde error.

Respuesta del mensaje

Los clientes pueden recibir mensajes publicados desde un grupo al que el cliente se ha unido o desde el servidor, que, funcionando en un rol de administración de servidores, envía mensajes a clientes o usuarios específicos.

  1. Mensaje de respuesta de un grupo:

    {
        "sequenceId": 1,
        "type": "message",
        "from": "group",
        "group": "<group_name>",
        "dataType": "json|text|binary",
        "data" : {} // The data format is based on the dataType
        "fromUserId": "abc"
    }
    
  2. Mensaje de respuesta del servidor:

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

Caso 1: envío de datos Hello World a la conexión a través de la API REST con Content-Type=text/plain

  • Un cliente WebSocket simple recibe un marco WebSocket de texto con datos: Hello World;

  • Un cliente WebSocket de PubSub recibe el mensaje en JSON:

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

Caso 2: envío de datos { "Hello" : "World"} a la conexión a través de la API REST con Content-Type=application/json

  • Un cliente WebSocket simple recibe un marco WebSocket de texto con datos en cadena: { "Hello" : "World"};

  • Un cliente WebSocket de PubSub recibe el mensaje en JSON:

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

Si la API REST envía una cadena Hello World mediante el tipo de contenido application/json, el cliente WebSocket simple recibe la cadena JSON "Hello World" encapsulada en ".

Caso 3: envío de datos binarios a la conexión a través de la API REST con Content-Type=application/octet-stream

  • Un cliente WebSocket simple recibe un marco de WebSocket binario con los datos binarios.

  • Un cliente WebSocket de PubSub recibe el mensaje en JSON:

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

Respuesta del sistema

El servicio Web PubSub puede devolver respuestas relacionadas con el sistema al cliente.

Respuesta de Pong

El servicio Web PubSub envía un mensaje pong al cliente cuando recibe un mensaje ping del cliente.

Formato:

{
    "type": "pong",
}

Conectado

Respuesta a la solicitud de conexión del cliente:

{
    "type": "system",
    "event": "connected",
    "userId": "user1",
    "connectionId": "abcdefghijklmnop",
    "reconnectionToken": "<token>"
}

Las propiedades connectionId y reconnectionToken se usan para la reconexión. Realice la solicitud de conexión con el URI para la reconexión:

wss://<service-endpoint>/client/hubs/<hub>?awps_connection_id=<connectionId>&awps_reconnection_token=<reconnectionToken>

Puede obtener más información en Recuperación de la conexión

Escenario desconectado

Respuesta cuando el servidor cierra la conexión o cuando el servicio rechaza la conexión de cliente:

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

Pasos siguientes

Use estos recursos para empezar a compilar su propia aplicación: