Руководство. Публикация и подписка сообщений между клиентами WebSocket с использованием подпротокола

В руководстве по созданию приложения чата вы узнали, как использовать API WebSocket для отправки и получения данных с помощью Azure Web PubSub. Для обмена данными между клиентом и службой протокол не требуется. Например, можно отправить любой тип данных, используя WebSocket.send()его, и сервер получает его так же, как это. Процесс API WebSocket прост в использовании, но функциональность ограничена. Например, нельзя указать имя события при отправке события на сервер или опубликовать сообщение другим клиентам вместо отправки на сервер. В этом руководстве описано, как использовать подпротокол для расширения функциональности клиента.

В этом руководстве описано следующее:

  • Создание экземпляра службы Web PubSub.
  • Создание полного URL-адреса для установки подключения WebSocket
  • публикация сообщений между клиентами WebSocket с использованием подпротокола.

Если у вас еще нет подписки Azure, создайте бесплатную учетную запись Azure, прежде чем начинать работу.

Необходимые компоненты

  • Используйте среду Bash в Azure Cloud Shell. Дополнительные сведения см . в кратком руководстве по Bash в Azure Cloud Shell.

  • Если вы предпочитаете выполнять справочные команды CLI локально, установите Azure CLI. Если вы работаете в Windows или macOS, Azure CLI можно запустить в контейнере Docker. Дополнительные сведения см. в статье Как запустить Azure CLI в контейнере Docker.

    • Если вы используете локальную установку, выполните вход в Azure CLI с помощью команды az login. Чтобы выполнить аутентификацию, следуйте инструкциям в окне терминала. Сведения о других возможностях, доступных при входе, см. в статье Вход с помощью Azure CLI.

    • Установите расширение Azure CLI при первом использовании, когда появится соответствующий запрос. Дополнительные сведения о расширениях см. в статье Использование расширений с Azure CLI.

    • Выполните команду az version, чтобы узнать установленную версию и зависимые библиотеки. Чтобы обновиться до последней версии, выполните команду az upgrade.

  • Для работы с этим руководством требуется Azure CLI версии 2.22.0 или выше. Если вы используете Azure Cloud Shell, последняя версия уже установлена.

Создание экземпляра Azure Web PubSub

Создание или изменение группы ресурсов

Группа ресурсов — это логический контейнер, в котором происходит развертывание ресурсов Azure и управление ими. Используйте команду az group create, чтобы создать группу ресурсов с именем myResourceGroup в расположенииeastus.

az group create --name myResourceGroup --location EastUS

Создание экземпляра Web PubSub

Запустите az extension add to install or upgrade the webpubsub extension to the current version.

az extension add --upgrade --name webpubsub

Используйте команду azure CLI az webpubsub create , чтобы создать web PubSub в созданной группе ресурсов. Следующая команда создает ресурс Free Web PubSub в группе ресурсов myResourceGroup в EastUS:

Важно!

Каждый ресурс Web PubSub должен иметь уникальное имя. В следующих примерах замените <your-unique-resource-name> именем своей службы Web PubSub.

az webpubsub create --name "<your-unique-resource-name>" --resource-group "myResourceGroup" --location "EastUS" --sku Free_F1

В выходных данных команды будут показаны свойства созданного ресурса. Запишите значения двух указанных ниже свойств.

  • Имя ресурса: имя, которое вы ввели для указанного выше параметра --name.
  • hostName: в примере имя узла <your-unique-resource-name>.webpubsub.azure.com/.

На данном этапе любые операции в этом новом ресурсе могут выполняться только с использованием вашей учетной записи Azure.

Получение ConnectionString для будущего использования

Важно!

Строка подключения содержит сведения об авторизации, требуемые для доступа приложения к службе Azure Web PubSub. Ключ доступа в строке подключения аналогичен паролю привилегированного пользователя для службы. В рабочих средах всегда следует тщательно защищать ключи доступа. Для безопасного управления ключами и их замены воспользуйтесь Azure Key Vault. Старайтесь не распространять ключи доступа среди других пользователей, жестко программировать их или где-то сохранять в виде обычного текста в открытом доступе для других пользователей. Меняйте свои ключи постоянно, если предполагаете, что они могут быть подобраны.

Выполните команду Azure CLI az webpubsub key, чтобы получить значение ConnectionString службы. Замените <your-unique-resource-name> заполнитель именем экземпляра Azure Web PubSub.

az webpubsub key show --resource-group myResourceGroup --name <your-unique-resource-name> --query primaryConnectionString --output tsv

Скопируйте строка подключения для последующего использования.

Скопируйте извлекаемый Подключение ionString и используйте далее в этом руководстве в качестве значения<connection_string>.

Настройка проекта

Необходимые компоненты

Использование подпротокола

Клиент может установить подключение к WebSocket по определенному подпротоколу. Служба Azure Web PubSub поддерживает подпротокол, вызываемую json.webpubsub.azure.v1 для предоставления клиентам возможности публиковать и подписываться непосредственно через службу Web PubSub вместо кругового пути к серверу вышестоящий. Сведения о подпротоколе см. в статье Поддерживаемый в Azure Web PubSub подпротокол JSON WebSocket.

Если вы используете другие имена протоколов, они будут игнорироваться службой и передаваться на сервер в обработчике событий подключения, позволяя вам создавать собственные протоколы.

Теперь создадим веб-приложение с использованием подпротокола json.webpubsub.azure.v1.

  1. Установка зависимостей

    mkdir logstream
    cd logstream
    dotnet new web
    dotnet add package Microsoft.Extensions.Azure
    dotnet add package Azure.Messaging.WebPubSub
    
  2. Создайте серверную часть для размещения API /negotiate и веб-страницы.

    Измените файл Program.cs, добавив приведенный ниже код.

    • Используйте AddAzureClients для добавления клиента службы и чтения строка подключения из конфигурации.
    • Добавьте app.UseStaticFiles(); до app.Run(); поддержки статических файлов.
    • И измените app.MapGet для создания маркера доступа клиента с помощью запросов /negotiate.
    using Azure.Messaging.WebPubSub;
    using Microsoft.Extensions.Azure;
    
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddAzureClients(s =>
    {
        s.AddWebPubSubServiceClient(builder.Configuration["Azure:WebPubSub:ConnectionString"], "stream");
    });
    
    var app = builder.Build();
    app.UseStaticFiles();
    app.MapGet("/negotiate", async context =>
    {
        var service = context.RequestServices.GetRequiredService<WebPubSubServiceClient>();
        var response = new
        {
            url = service.GetClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" }).AbsoluteUri
        };
        await context.Response.WriteAsJsonAsync(response);
    });
    
    app.Run();
    
  3. Создание веб-страницы

    Создайте HTML-страницу с приведенным ниже содержимым и сохраните ее как wwwroot/index.html.

    <html>
      <body>
        <div id="output"></div>
        <script>
          (async function () {
            let res = await fetch('/negotiate')
            let data = await res.json();
            let ws = new WebSocket(data.url, 'json.webpubsub.azure.v1');
            ws.onopen = () => {
              console.log('connected');
            };
    
            let output = document.querySelector('#output');
            ws.onmessage = event => {
              let d = document.createElement('p');
              d.innerText = event.data;
              output.appendChild(d);
            };
          })();
        </script>
      </body>
    </html>                                                                
    

    Приведенный выше код подключается к службе и выводит любое сообщение, полученное на страницу. Основное изменение заключается в том, что при создании соединения WebSocket мы указываем подпротокол.

  4. Запуск сервера

    Мы используем средство Secret Manager для .NET Core, чтобы настроить строку подключения. Выполните приведенную ниже команду, заменив <connection_string> строкой, полученной на предыдущем шаге, и откройте http://localhost:5000/index.html в браузере.

    dotnet user-secrets init
    dotnet user-secrets set Azure:WebPubSub:ConnectionString "<connection-string>"
    dotnet run
    

    Если вы используете Chrome, вы можете нажать клавишу F12 или щелкнуть правой кнопкой мыши ->Проверить> средства разработчика и выбрать вкладку "Сеть". Загрузите веб-страницу и вы увидите, что установлено подключение WebSocket. Выберите, чтобы проверить подключение WebSocket, вы увидите следующее connected сообщение о событии, полученное в клиенте. Как видите, вы можете сгенерировать connectionId для этого клиента.

    {"type":"system","event":"connected","userId":null,"connectionId":"<the_connection_id>"}
    

Как видите, с помощью подпротокола можно получить метаданные подключения, если оно имеет значение connected.

Теперь клиент получает сообщение JSON вместо обычного текста. Сообщение JSON содержит дополнительные сведения, такие как тип и источник сообщения. Эти сведения можно использовать для дальнейшей обработки сообщения (например, отобразить сообщение в другом стиле, если оно получено из другого источника). Это описано следующих разделах.

Публикация сообщений от клиента

В руководстве по созданию приложения чата, когда клиент отправляет сообщение через подключение WebSocket к службе Web PubSub, служба активирует событие пользователя на стороне сервера. При использовании подпротокол клиент имеет больше функций, отправляя сообщение JSON. Например, вы можете публиковать сообщения непосредственно из клиента через службу Web PubSub другим клиентам.

Это полезно, если требуется потоковая передача большого объема данных другим клиентам в режиме реального времени. Давайте воспользуемся этой возможностью, чтобы создать приложение потоковой передачи журналов, которое может выполнять потоковую передачу журналов консоли в браузер в реальном времени.

  1. Создание программы потоковой передачи

    Создайте программу stream:

    mkdir stream
    cd stream
    dotnet new console
    

    Измените Program.cs, добавив следующее содержимое:

    using System;
    using System.Net.Http;
    using System.Net.WebSockets;
    using System.Text;
    using System.Text.Json;
    using System.Threading.Tasks;
    
    namespace stream
    {
        class Program
        {
            private static readonly HttpClient http = new HttpClient();
            static async Task Main(string[] args)
            {
                // Get client url from remote
                var stream = await http.GetStreamAsync("http://localhost:5000/negotiate");
                var url = (await JsonSerializer.DeserializeAsync<ClientToken>(stream)).url;
                var client = new ClientWebSocket();
                client.Options.AddSubProtocol("json.webpubsub.azure.v1");
    
                await client.ConnectAsync(new Uri(url), default);
    
                Console.WriteLine("Connected.");
                var streaming = Console.ReadLine();
                while (streaming != null)
                {
                    if (!string.IsNullOrEmpty(streaming))
                    {
                        var message = JsonSerializer.Serialize(new
                        {
                            type = "sendToGroup",
                            group = "stream",
                            data = streaming + Environment.NewLine,
                        });
                        Console.WriteLine("Sending " + message);
                        await client.SendAsync(Encoding.UTF8.GetBytes(message), WebSocketMessageType.Text, true, default);
                    }
    
                    streaming = Console.ReadLine();
                }
    
                await client.CloseAsync(WebSocketCloseStatus.NormalClosure, null, default);
            }
    
            private sealed class ClientToken
            {
                public string url { get; set; }
            }
        }
    }
    
    

    Вы можете увидеть, что здесь есть новая концепция "группа". Группа — это логическая концепция в концентраторе, где можно опубликовать сообщение для группы подключений. В концентраторе можно создать несколько групп. Один клиент может одновременно подписаться на несколько групп. При использовании подпротокола можно опубликовать данные только в группе, а не во всем концентраторе. Сведения о терминах см. в статье об основных понятиях.

  2. Так как мы используем здесь группу, нам также нужно обновить веб-страницу index.html, чтобы присоединиться к группе, если подключение WebSocket устанавливается в пределах обратного вызова ws.onopen.

    let ackId = 0;
    ws.onopen = () => {
      console.log('connected');
      ws.send(JSON.stringify({
        type: 'joinGroup',
        group: 'stream',
        ackId: ++ackId
      }));
    };
    

    Как показано, клиент присоединяется к группе, отправляя сообщение типа joinGroup.

  3. Также можно немного обновить логику обратного вызова ws.onmessage, чтобы проанализировать ответ JSON и вывести сообщения только от группы stream, используя аналог принтера потока в реальном времени.

    ws.onmessage = event => {
      let message = JSON.parse(event.data);
      if (message.type === 'message' && message.group === 'stream') {
        let d = document.createElement('span');
        d.innerText = message.data;
        output.appendChild(d);
        window.scrollTo(0, document.body.scrollHeight);
      }
    };
    
  4. По соображениям безопасности клиент по умолчанию не может публиковать данные или подписываться на группу. Поэтому вы заметили, что при создании маркера мы задали roles клиенту значение:

    Задайте roles при GenerateClientAccessUri в Startup.cs, как показано ниже:

    service.GenerateClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" })
    
  5. Наконец, примените нужный стиль к index.html для отображения в удобном формате.

    <html>
    
      <head>
        <style>
          #output {
            white-space: pre;
            font-family: monospace;
          }
        </style>
      </head>
    

Теперь запустите приведенный ниже код и введите любой текст, и они отображаются в браузере в режиме реального времени:

ls -R | dotnet run

# Or call `dir /s /b | dotnet run` when you are using CMD under Windows

Или вы можете замедлить вывод текста, чтобы увидеть, как данные передаются в браузер в реальном времени.

for i in $(ls -R); do echo $i; sleep 0.1; done | dotnet run

Полный пример кода для этого учебника можно найти здесь.

Следующие шаги

В этом руководстве вы узнаете, как подключиться к службе Web PubSub и как публиковать сообщения в подключенных клиентах с помощью подпротокола.

Чтобы узнать больше об использовании службы, ознакомьтесь с другими учебниками.