Subprotocolo WebSocket JSON confiável do Azure Web PubSub

O subprotocolo JSON WebSocket, json.reliable.webpubsub.azure.v1, permite a troca altamente confiável de mensagens de publicação/assinatura diretamente entre clientes através do serviço sem uma viagem de ida e volta para o servidor upstream.

Este documento descreve o subprotocolo json.reliable.webpubsub.azure.v1.

Quando as conexões do cliente WebSocket caem devido a problemas intermitentes de rede, as mensagens podem ser perdidas. Em um sistema pub/sub, os editores são dissociados dos assinantes e podem não detetar a perda de conexão ou mensagem de um assinante.

Para superar problemas intermitentes de rede e manter a entrega confiável de mensagens, você pode usar o subprotocolo WebPubSub json.reliable.webpubsub.azure.v1 do Azure para criar um cliente WebSocket PubSub confiável.

Um cliente Reliable PubSub WebSocket pode:

  • Recupere uma conexão de problemas de rede intermitentes.
  • recuperar da perda de mensagens.
  • Ingresse em um grupo usando solicitações de ingresso.
  • Saia de um grupo usando solicitações de licença.
  • Publique mensagens diretamente em um grupo usando solicitações de publicação.
  • Transmita mensagens diretamente para um grupo usando pedidos de streaming.
  • Encaminhe mensagens diretamente para manipuladores de eventos upstream usando solicitações de eventos.

Por exemplo, você pode criar um cliente Reliable PubSub WebSocket com o seguinte código JavaScript:

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

Consulte Como criar clientes confiáveis para implementar a reconexão e a confiabilidade da mensagem para clientes de publicador e assinante.

Quando o cliente está usando esse subprotocolo, os quadros de dados de entrada e saída devem conter cargas úteis JSON.

Permissões

Um cliente PubSub WebSocket só pode publicar para outros clientes quando é autorizado. Os roles atribuídos ao cliente determinam as permissões concedidas ao cliente:

Role Permissão
Não especificado O cliente pode enviar solicitações de eventos.
webpubsub.joinLeaveGroup O cliente pode entrar/sair de qualquer grupo.
webpubsub.sendToGroup O cliente pode publicar mensagens em qualquer grupo.
webpubsub.joinLeaveGroup.<group> O cliente pode entrar/sair do grupo <group>.
webpubsub.sendToGroup.<group> O cliente pode publicar mensagens no grupo <group>.
webpubsub.joinLeaveGroups.<pattern> O cliente pode juntar-se/sair de qualquer grupo cujo nome corresponda <pattern> (ver padrões de funções de grupo Wildcard).
webpubsub.sendToGroups.<pattern> O cliente pode publicar mensagens para qualquer grupo cujo nome corresponda <pattern> (ver Padrões de papéis de grupo curinga).

O servidor pode conceder ou revogar dinamicamente permissões de cliente por meio de APIs REST ou SDKs de servidor.

Observação

Os papéis coringa (por exemplo, webpubsub.sendToGroups.<pattern>) ainda não são suportados em APIs REST ou SDKs de servidor durante a execução.

Pedidos do

Junte-se a grupos

Formato:

{
    "type": "joinGroup",
    "group": "<group_name>",
    "ackId" : 1
}
  • ackId é a identidade de cada pedido e deve ser única. O serviço envia uma mensagem de resposta ack para notificar o resultado do processo da solicitação. Para obter detalhes, consulte AckId e Ack Response

Sair dos grupos

Formato:

{
    "type": "leaveGroup",
    "group": "<group_name>",
    "ackId" : 1
}
  • ackId é a identidade de cada pedido e deve ser única. O serviço envia uma mensagem de resposta ack para notificar o resultado do processo da solicitação. Para obter detalhes, consulte AckId e Ack Response

Publicar mensagens

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 é a identidade de cada pedido e deve ser única. O serviço envia uma mensagem de resposta ack para notificar o resultado do processo da solicitação. Para obter detalhes, consulte AckId e Ack Response
  • noEcho é opcional. Se definida como true, essa mensagem não será repercutida na mesma conexão. Se não estiver definido, o valor padrão será false.
  • dataType pode ser definido como json, textou binary:
    • json: data pode ser qualquer tipo que o JSON suporta e será publicado como o que é; Se dataType não for especificado, o padrão será json.
    • text: data deve estar em formato de cadeia de caracteres, e os dados da cadeia de caracteres serão publicados;
    • binary: data deve estar no formato base64, e os dados binários serão publicados;

Caso 1: publicar dados de texto:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "dataType" : "text",
    "data": "text data",
    "ackId": 1
}
  • Os clientes do subprotocolo recebem <group_name> :
{
    "type": "message",
    "from": "group",
    "group": "<group_name>",
    "dataType" : "text",
    "data" : "text data"
}
  • Os clientes WebSocket simples em <group_name> receber a cadeia de caracteres text data.

Caso 2: publicar dados JSON:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "dataType" : "json",
    "data": {
        "hello": "world"
    }
}
  • Os clientes do subprotocolo recebem <group_name> :
{
    "type": "message",
    "from": "group",
    "group": "<group_name>",
    "dataType" : "json",
    "data" : {
        "hello": "world"
    }
}
  • Os clientes WebSocket simples em <group_name> receber a seqüência de caracteres {"hello": "world"}serializada .

Caso 3: publicar dados binários:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "dataType" : "binary",
    "data": "<base64_binary>",
    "ackId": 1
}
  • Os clientes do subprotocolo recebem <group_name> :
{
    "type": "message",
    "from": "group",
    "group": "<group_name>",
    "dataType" : "binary",
    "data" : "<base64_binary>", 
}
  • Os clientes WebSocket simples em <group_name> receber os dados binários no quadro binário.

Iniciar transmitir mensagens

Para iniciar uma transmissão em grupo, envie um sendToGroup pedido à stream propriedade. Um pedido de início de stream não contém data, dataType, ou ackId.

Formato:

{
    "type": "sendToGroup",
    "group": "<group_name>",
    "noEcho": true|false,
    "stream": {
        "streamId": "<stream_id>",
        "idleTimeoutMs": 300000
    }
}
  • stream.streamId é o identificador do fluxo lógico. Deve ser uma string não vazia e deve ser única entre os fluxos ativos na mesma ligação do cliente. Recomenda-se que as bibliotecas clientes gerem um valor globalmente único, como um GUID ou UUID.
  • stream.idleTimeoutMs é opcional. Se especificado, deve ser maior que 0. Se for omitido, o padrão do serviço é 300000 milissegundos. O valor é um timeout inativo, não uma vida útil total do fluxo. Envie dados do fluxo, envie um stream keep epalive, ou termine o fluxo antes que este timeout expire, quando a aplicação precisa de manter o stream aberto.
  • noEcho é opcional. Se definidas como verdadeiras, as mensagens do stream não são enviadas de volta para a mesma ligação. Se não estiver definido, o valor padrão será false.

Quando o fluxo é aceite, o cliente recebe uma resposta de ack do fluxo com expectedSequenceId definido para 1.

Enviar dados em streaming

Para enviar dados de fluxo, envie um streamData pedido com streamId, streamSequenceId, dataType, e data.

Formato:

{
    "type": "streamData",
    "streamId": "<stream_id>",
    "streamSequenceId": 1,
    "dataType" : "json|text|binary",
    "data": {}
}
  • streamId identifica um fluxo ativo na mesma ligação ao cliente.
  • streamSequenceId é um número uint64 positivo. O primeiro fragmento de dados num fluxo usa 1, e cada fragmento de dados seguinte para o mesmo streamId aumenta exatamente 1em .
  • dataType pode ser definido como json, text, ou binary, com as mesmas regras de codificação de dados que publicar mensagens.

Para manter um fluxo ativo sem entregar dados aos assinantes, envie um streamData pedido apenas type com e streamId.

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

Fim das mensagens em streaming

Para terminar uma transmissão, envie um streamEnd pedido.

Formato:

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

Para terminar um fluxo com um erro definido pela aplicação, inclua a propriedade opcional error .

{
    "type": "streamEnd",
    "streamId": "<stream_id>",
    "error": {
        "message": "<error_detail>",
        "userErrorCode": "<application_error_code>"
    }
}
  • error.message é uma mensagem de erro opcional legível por humanos.
  • error.userErrorCode é um código de erro opcional definido pela aplicação.

Quando o fluxo é encerrado, o editor recebe uma resposta de encerramento do fluxo.

Enviar 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 
}
  • ackId é a identidade de cada pedido e deve ser única. O serviço envia uma mensagem de resposta ack para notificar o resultado do processo da solicitação. Para obter detalhes, consulte AckId e Ack Response

dataType pode ser um dos text, binaryou json:

  • json: os dados podem ser de qualquer tipo que json suporta e serão publicados como o que são; O padrão é json.
  • text: os dados estão em formato de cadeia de caracteres e os dados da cadeia de caracteres serão publicados;
  • binary: os dados estão no formato base64 e os dados binários serão publicados;

Caso 1: enviar evento com dados de texto:

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

O manipulador de eventos upstream recebe dados semelhantes 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

A Content-Type solicitação HTTP para o CloudEvents é text/plain quando dataType é text.

Caso 2: enviar evento com dados JSON:

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

O manipulador de eventos upstream recebe dados semelhantes 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"
}

O Content-Type para a solicitação HTTP do CloudEvents é application/json quando dataType é json

Caso 3: enviar evento com dados binários:

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

O manipulador de eventos upstream recebe dados semelhantes 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

A Content-Type solicitação HTTP para o CloudEvents é application/octet-stream quando dataType é binary. O quadro WebSocket pode ser text formatado para quadros de mensagem de texto ou binários codificados UTF8 para binary quadros de mensagem.

O serviço Web PubSub recusa o cliente se a mensagem não corresponder ao formato descrito.

Ping

Formato:

{
    "type": "ping",
}

O cliente pode enviar uma ping mensagem para o serviço para habilitar o serviço Web PubSub para detetar a vivacidade do cliente.

Sequência Ack

Formato:

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

O cliente Reliable PubSub WebSocket deve enviar uma mensagem ack de sequência assim que receber uma mensagem do serviço. Para obter mais informações, consulte Como criar clientes confiáveis

  • sequenceId é um número uint64 incremental da mensagem recebida.

Respostas

As mensagens recebidas pelo cliente podem ser de vários tipos: ack, message, system, pong, streamAck, streamNack, e streamClosed. As mensagens com o tipo message têm sequenceId propriedade. O cliente deve enviar um Sequence Ack para o serviço assim que receber uma mensagem.

Resposta Ack

Quando a solicitação contiver ackId, o serviço retornará uma resposta ack para essa solicitação. A implementação do cliente deve lidar com esse mecanismo ack, incluindo aguardar a resposta ack usando uma asyncawait operação, e ter um manipulador de tempo limite quando a resposta ack não é recebida durante um determinado período.

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

A implementação do cliente DEVE sempre verificar se o é success ou true primeirofalse. Somente quando success o cliente lê false de error.

Resposta à mensagem

Os clientes podem receber mensagens publicadas de um grupo ao qual o cliente aderiu ou do servidor, que, operando em uma função de gerenciamento de servidor, envia mensagens para clientes ou usuários específicos.

  1. A mensagem de resposta de um 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. A mensagem de resposta do servidor:

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

Caso 1: Enviando dados Hello World para a conexão através da API REST com Content-Type=text/plain

  • Um cliente WebSocket simples recebe um quadro WebSocket de texto com dados: Hello World;

  • Um cliente PubSub WebSocket recebe a mensagem em JSON:

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

Caso 2: Enviando dados { "Hello" : "World"} para a conexão através da API REST com Content-Type=application/json

  • Um cliente WebSocket simples recebe um quadro WebSocket de texto com dados stringificados: { "Hello" : "World"};

  • Um cliente PubSub WebSocket recebe a mensagem em JSON:

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

Se a API REST estiver enviando uma cadeia de caracteres Hello World usando application/json o tipo de conteúdo, o cliente WebSocket simples receberá a cadeia de caracteres "Hello World" JSON encapsulada em ".

Caso 3: Enviando dados binários para a conexão através da API REST com Content-Type=application/octet-stream

  • Um cliente WebSocket simples recebe um quadro WebSocket binário com os dados binários.

  • Um cliente PubSub WebSocket recebe a mensagem em JSON:

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

Resposta de mensagens em streaming

Quando uma mensagem pertence a um fluxo, a mensagem de grupo contém uma stream propriedade. O fiável sequenceId mantém-se com escopo de ligação e é diferente de stream.streamSequenceId.

{
    "sequenceId": 1,
    "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 é o identificador lógico do fluxo.
  • stream.streamSequenceId é o número de sequência da mensagem no fluxo.
  • stream.endOfStream é opcional. Quando definido para true, a mensagem é a mensagem terminal do fluxo.
  • stream.error é opcional e está presente apenas quando o fluxo termina com um erro. userErrorCode está presente apenas para UserError.

Resposta ao fluxo de água

O serviço envia uma streamAck resposta para confirmar dados de fluxo aceites e para reportar o próximo ID de sequência de fluxo que espera.

Formato:

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

Resposta do nack do ribeiro

O serviço envia uma streamNack resposta para um erro de fluxo retentável.

Formato:

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

Resposta de fluxo fechado

O serviço envia uma streamClosed resposta quando o fluxo do lado da editora é encerrado.

Formato:

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

A error propriedade é omitida quando o fluxo de água está normalmente fechado.

Resposta do sistema

O serviço Web PubSub pode retornar respostas relacionadas ao sistema para o cliente.

Resposta Pong

O serviço Web PubSub envia uma pong mensagem para o cliente quando recebe uma ping mensagem do cliente.

Formato:

{
    "type": "pong",
}

Ligado

A resposta à solicitação de conexão do cliente:

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

connectionId e reconnectionToken são usados para reconexão. Faça solicitação de conexão com uri para reconexão:

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

Encontre mais detalhes em Recuperação de Conexão

Desligado

A resposta quando o servidor fecha a conexão ou quando o serviço recusa a conexão do cliente:

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

Próximos passos

Use estes recursos para começar a criar seu próprio aplicativo: