Samouczek: publikowanie i subskrybowanie komunikatów między klientami protokołu WebSocket przy użyciu podprotocol

W samouczku Tworzenie aplikacji do czatu przedstawiono sposób wysyłania i odbierania danych za pomocą interfejsów API protokołu WebSocket na platformie Azure Web PubSub. Jeśli klient komunikuje się z usługą, nie jest potrzebny żaden protokół. Na przykład można wysłać dowolny typ danych przy użyciu polecenia WebSocket.send(), a serwer odbiera je tak samo, jak jest. Proces interfejsów API protokołu WebSocket jest łatwy w użyciu, ale funkcjonalność jest ograniczona. Na przykład nie można określić nazwy zdarzenia podczas wysyłania zdarzenia na serwer lub publikowania komunikatu do innych klientów zamiast wysyłania go na serwer. Z tego samouczka dowiesz się, jak za pomocą podprotocol rozszerzyć funkcjonalność klienta.

Z tego samouczka dowiesz się, jak wykonywać następujące czynności:

  • Tworzenie wystąpienia usługi Web PubSub
  • Generowanie pełnego adresu URL w celu ustanowienia połączenia protokołu WebSocket
  • Publikowanie komunikatów między klientami protokołu WebSocket przy użyciu podprotocol

Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto platformy Azure.

Wymagania wstępne

  • Ta konfiguracja wymaga wersji 2.22.0 lub nowszej interfejsu wiersza polecenia platformy Azure. W przypadku korzystania z usługi Azure Cloud Shell najnowsza wersja jest już zainstalowana.

Tworzenie wystąpienia usługi Azure Web PubSub

Tworzenie grupy zasobów

Grupa zasobów to logiczny kontener przeznaczony do wdrażania zasobów platformy Azure i zarządzania nimi. Użyj polecenia az group create, aby utworzyć grupę zasobów o nazwie myResourceGroup w eastus lokalizacji.

az group create --name myResourceGroup --location EastUS

Tworzenie wystąpienia usługi Web PubSub

Uruchom polecenie az extension add , aby zainstalować lub uaktualnić rozszerzenie webpubsub do bieżącej wersji.

az extension add --upgrade --name webpubsub

Użyj polecenia az webpubsub create interfejsu wiersza polecenia platformy Azure, aby utworzyć internetowy pubSub w utworzonej grupie zasobów. Następujące polecenie tworzy zasób Free Web PubSub w grupie zasobów myResourceGroup w regionie EastUS:

Ważne

Każdy zasób Web PubSub musi mieć unikatową nazwę. Zastąp <ciąg your-unique-resource-name> nazwą usługi Web PubSub w poniższych przykładach.

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

Dane wyjściowe tego polecenia pokazują właściwości nowo utworzonego zasobu. Zanotuj dwie poniższe właściwości:

  • Nazwa zasobu: nazwa podana powyżej parametru --name .
  • hostName: w przykładzie nazwa hosta to <your-unique-resource-name>.webpubsub.azure.com/.

W tym momencie Twoje konto platformy Azure jest jedynym autoryzowanym do wykonywania jakichkolwiek operacji na tym nowym zasobie.

Pobieranie Połączenie ionString do użycia w przyszłości

Ważne

Parametry połączenia zawiera informacje o autoryzacji wymagane przez aplikację w celu uzyskania dostępu do usługi Azure Web PubSub. Klucz dostępu wewnątrz parametry połączenia jest podobny do hasła głównego usługi. W środowiskach produkcyjnych należy zawsze zachować ostrożność w celu ochrony kluczy dostępu. Usługa Azure Key Vault umożliwia bezpieczne zarządzanie kluczami i obracanie ich. Unikaj dystrybuowania kluczy dostępu do innych użytkowników, kodowania ich lub zapisywania ich w dowolnym miejscu w postaci zwykłego tekstu, który jest dostępny dla innych użytkowników. Obracanie kluczy, jeśli uważasz, że mogły one zostać naruszone.

Użyj polecenia az webpubsub key interfejsu wiersza polecenia platformy Azure, aby uzyskać Połączenie ionString usługi. Zastąp <your-unique-resource-name> symbol zastępczy nazwą wystąpienia usługi Azure Web PubSub.

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

Skopiuj parametry połączenia do późniejszego użycia.

Skopiuj pobrany Połączenie ionString i użyj go w dalszej części tego samouczka <connection_string>jako wartości .

Konfigurowanie projektu

Wymagania wstępne

Używanie podprotokolu

Klient może uruchomić połączenie protokołu WebSocket przy użyciu określonego podprotokolu. Usługa Azure Web PubSub obsługuje podprotokol wywoływany json.webpubsub.azure.v1 w celu umożliwienia klientom publikowania/subskrybowania bezpośrednio za pośrednictwem usługi Web PubSub zamiast rundy na serwerze nadrzędnym. Aby uzyskać szczegółowe informacje na temat podprotokolu subprotocol obsługiwanego przez usługę Web PubSub platformy Azure, zobacz subprotocol obsługiwany kod JSON WebSocket.

Jeśli używasz innych nazw protokołów, zostaną one zignorowane przez usługę i przekazywanie do serwera w programie obsługi zdarzeń połączenia, aby można było utworzyć własne protokoły.

Teraz utwórzmy aplikację internetową przy użyciu podprotokolu json.webpubsub.azure.v1 .

  1. Instalowanie zależności

    mkdir logstream
    cd logstream
    dotnet new web
    dotnet add package Microsoft.Extensions.Azure
    dotnet add package Azure.Messaging.WebPubSub
    
  2. Utwórz stronę serwera do hostowania interfejsu /negotiate API i strony internetowej.

    Zaktualizuj Program.cs za pomocą poniższego kodu.

    • Użyj AddAzureClients polecenia , aby dodać klienta usługi i odczytać parametry połączenia z konfiguracji.
    • Dodaj app.UseStaticFiles(); element przed app.Run(); , aby obsługiwać pliki statyczne.
    • I zaktualizuj app.MapGet , aby wygenerować token dostępu klienta przy użyciu /negotiate żądań.
    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. Tworzenie strony internetowej

    Utwórz stronę HTML z poniższą zawartością i zapisz ją jako 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>                                                                
    

    Powyższy kod łączy się z usługą i wyświetla wszelkie komunikaty odebrane na stronie. Główną zmianą jest określenie podprotokolu podczas tworzenia połączenia protokołu WebSocket.

  4. Uruchamianie serwera

    Do ustawienia parametry połączenia używamy narzędzia Secret Manager dla platformy .NET Core. Uruchom poniższe polecenie, zastępując <connection_string> element pobrany w poprzednim kroku i otwórz http://localhost:5000/index.html w przeglądarce:

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

    Jeśli używasz przeglądarki Chrome, możesz nacisnąć klawisz F12 lub kliknąć prawym przyciskiem myszy pozycję ->Inspect -Developer Tools (Sprawdź ->Developer Tools) i wybrać kartę Sieć. Załaduj stronę internetową i zobaczysz, że połączenie webSocket zostało nawiązane. Wybierz, aby sprawdzić połączenie protokołu WebSocket. W kliencie zostanie wyświetlony poniższy connected komunikat o zdarzeniu. Zobaczysz, że możesz pobrać connectionId wygenerowany dla tego klienta.

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

Widać, że za pomocą podprotocol można uzyskać metadane połączenia, gdy połączenie to connected.

Klient otrzymuje teraz komunikat JSON zamiast zwykłego tekstu. Komunikat JSON zawiera więcej informacji, takich jak typ i źródło komunikatu. Dzięki temu możesz użyć tych informacji, aby wykonać więcej przetwarzania komunikatu (na przykład wyświetlić komunikat w innym stylu, jeśli pochodzi z innego źródła), które można znaleźć w kolejnych sekcjach.

Publikowanie komunikatów z klienta

W samouczku Tworzenie aplikacji czatu, gdy klient wysyła komunikat za pośrednictwem połączenia WebSocket z usługą Web PubSub, usługa wyzwala zdarzenie użytkownika po stronie serwera. W przypadku podprotocol klient ma więcej funkcji, wysyłając komunikat JSON. Można na przykład publikować komunikaty bezpośrednio z klienta za pośrednictwem usługi Web PubSub do innych klientów.

Jest to przydatne, jeśli chcesz przesyłać strumieniowo dużą ilość danych do innych klientów w czasie rzeczywistym. Użyjmy tej funkcji, aby utworzyć aplikację do przesyłania strumieniowego dzienników, która może przesyłać strumieniowo dzienniki konsoli do przeglądarki w czasie rzeczywistym.

  1. Tworzenie programu przesyłania strumieniowego

    Utwórz stream program:

    mkdir stream
    cd stream
    dotnet new console
    

    Zaktualizuj Program.cs przy użyciu następującej zawartości:

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

    W tym miejscu możesz zobaczyć, że istnieje nowa koncepcja "grupa". Grupa to koncepcja logiczna w centrum, w którym można opublikować komunikat w grupie połączeń. W centrum można mieć wiele grup, a jeden klient może jednocześnie subskrybować wiele grup. W przypadku korzystania z podprotocol można publikować tylko w grupie zamiast emitować do całego centrum. Aby uzyskać szczegółowe informacje na temat terminów, zapoznaj się z podstawowymi pojęciami.

  2. Ponieważ w tym miejscu używamy grupy, musimy również zaktualizować stronę index.html internetową, aby dołączyć do grupy po nawiązaniu połączenia protokołu WebSocket wewnątrz ws.onopen wywołania zwrotnego.

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

    Klient dołącza do grupy, wysyłając komunikat w joinGroup typie.

  3. Zaktualizuj również logikę ws.onmessage wywołania zwrotnego nieco, aby przeanalizować odpowiedź JSON i wydrukować komunikaty tylko z stream grupy, tak aby działał jako drukarka strumienia na żywo.

    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. W celu rozważenia zabezpieczeń klient domyślnie nie może publikować ani subskrybować grupy samodzielnie. Zauważyliśmy więc, że ustawiliśmy roles klienta podczas generowania tokenu:

    Ustaw wartość w przypadku roles , gdy GenerateClientAccessUri w pliku Startup.cs jak poniżej:

    service.GenerateClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" })
    
  5. Na koniec zastosuj również jakiś styl, aby index.html dobrze się wyświetlał.

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

Teraz uruchom poniższy kod i wpisz dowolny tekst i są one wyświetlane w przeglądarce w czasie rzeczywistym:

ls -R | dotnet run

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

Możesz też zwolnić dane, aby zobaczyć, że dane są przesyłane strumieniowo do przeglądarki w czasie rzeczywistym:

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

Kompletny przykład kodu tego samouczka można znaleźć tutaj.

Następne kroki

Ten samouczek zawiera podstawowe informacje na temat nawiązywania połączenia z usługą Web PubSub oraz publikowania komunikatów na połączonych klientach przy użyciu podprotocol.

Zapoznaj się z innymi samouczkami, aby dowiedzieć się więcej na temat korzystania z usługi.