Dela via


Självstudie: Skapa en serverlös chattapp i realtid med Azure Functions och Azure Web PubSub-tjänsten

Tjänsten Azure Web PubSub hjälper dig att enkelt skapa webbprogram för meddelanden i realtid med hjälp av WebSockets och mönstret publicera-prenumerera. Azure Functions är en serverlös plattform som gör att du kan köra din kod utan att behöva hantera någon infrastruktur. I den här självstudien får du lära dig hur du använder Tjänsten Azure Web PubSub och Azure Functions för att skapa ett serverlöst program med meddelanden i realtid och mönstret publicera-prenumerera.

I den här tutorialen lär du dig följande:

  • Skapa en serverlös chattapp i realtid
  • Arbeta med Web PubSub-funktionsutlösarbindningar och utdatabindningar
  • Distribuera funktionen till Azure-funktionsappen
  • Konfigurera Azure-autentisering
  • Konfigurera Web PubSub Event Handler för att dirigera händelser och meddelanden till programmet

Viktigt!

Råa anslutningssträng visas endast i den här artikeln i demonstrationssyfte.

En anslutningssträng innehåller den auktoriseringsinformation som krävs för att ditt program ska få åtkomst till Azure Web PubSub-tjänsten. Åtkomstnyckeln i anslutningssträng liknar ett rotlösenord för din tjänst. Skydda alltid dina åtkomstnycklar i produktionsmiljöer. Använd Azure Key Vault för att hantera och rotera dina nycklar säkert och säkra din anslutning med WebPubSubServiceClient.

Undvik att distribuera åtkomstnycklar till andra användare, hårdkoda dem eller spara dem någonstans i klartext som är åtkomlig för andra. Rotera dina nycklar om du tror att de har komprometterats.

Förutsättningar

Om du inte har något Azure-konto skapar du ett kostnadsfritt konto innan du börjar.

Logga in på Azure

Logga in på Azure Portal på https://portal.azure.com/ med ditt Azure-konto.

Skapa en Azure Web PubSub-tjänstinstans

Ditt program ansluter till en Web PubSub-tjänstinstans i Azure.

  1. Välj knappen Nytt högst upp till vänster i Azure-portalen. På skärmen Nytt skriver du Web PubSub i sökrutan och trycker på Retur. (Du kan också söka i Azure Web PubSub från Web kategorin.)

    Skärmbild av sökning i Azure Web PubSub i portalen.

  2. Välj Web PubSub i sökresultatet och välj sedan Skapa.

  3. Ange följande inställningar.

    Inställning Föreslaget värde Beskrivning
    Resursnamn Globalt unikt namn Det globalt unika namn som identifierar din nya Web PubSub-tjänstinstans. Giltiga tecken är a-z, A-Z, 0-9och -.
    Prenumeration Din prenumeration Den Azure-prenumeration under vilken den här nya Web PubSub-tjänstinstansen skapas.
    Resursgrupp minResursgrupp Namn på den nya resursgrupp där du vill skapa din Web PubSub-tjänstinstans.
    Läge Västra USA Välj en region nära dig.
    Prisnivå Kostnadsfri Du kan prova tjänsten Azure Web PubSub kostnadsfritt. Läs mer om prisnivåer för Azure Web PubSub-tjänsten
    Antal enheter - Antal enheter anger hur många anslutningar din Web PubSub-tjänstinstans kan acceptera. Varje enhet stöder högst 1 000 samtidiga anslutningar. Det kan bara konfigureras på Standard-nivån.

    Skärmbild av hur du skapar Azure Web PubSub-instansen i portalen.

  4. Välj Skapa för att börja distribuera instansen av Web PubSub-tjänsten.

Skapa funktionerna

  1. Kontrollera att du har Azure Functions Core Tools installerat. Skapa sedan en tom katalog för projektet. Kör kommandot i den här arbetskatalogen.

    func init --worker-runtime javascript --model V4
    
  2. Installera Microsoft.Azure.WebJobs.Extensions.WebPubSub.

    Bekräfta och uppdatera host.jsontilläggetBundle till version 4.* eller senare för att få support för Web PubSub.

    {
      "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.*, 5.0.0)"
      }
    }
    
  3. Skapa en index funktion för att läsa och vara värd för en statisk webbsida för klienter.

    func new -n index -t HttpTrigger
    
    • Uppdatera src/functions/index.js och kopiera följande koder.
      const { app } = require('@azure/functions');
      const { readFile } = require('fs/promises');
      
      app.http('index', {
          methods: ['GET', 'POST'],
          authLevel: 'anonymous',
          handler: async (context) => {
              const content = await readFile('index.html', 'utf8', (err, data) => {
                  if (err) {
                      context.err(err)
                      return
                  }
              });
      
              return { 
                  status: 200,
                  headers: { 
                      'Content-Type': 'text/html'
                  }, 
                  body: content, 
              };
          }
      });
      
  4. Skapa en negotiate funktion som hjälper klienter att hämta url:en för tjänstanslutning med åtkomsttoken.

    func new -n negotiate -t HttpTrigger
    

    Anmärkning

    I det här exemplet använder vi användaridentitetshuvudet för x-ms-client-principal-name för att hämta userId. Och detta fungerar inte i en lokal funktion. Du kan göra den tom eller ändra till andra sätt att hämta eller generera userId när du spelar lokalt. Låt klienten till exempel skriva in ett användarnamn och skicka det som ?user={$username} i frågan när funktionen negotiate anropas för att hämta tjänstanslutningens URL. Och i negotiate funktionen anger du userId med värdet {query.user}.

    • Uppdatera src/functions/negotiate och kopiera följande koder.
      const { app, input } = require('@azure/functions');
      
      const connection = input.generic({
          type: 'webPubSubConnection',
          name: 'connection',
          userId: '{headers.x-ms-client-principal-name}',
          hub: 'simplechat'
      });
      
      app.http('negotiate', {
          methods: ['GET', 'POST'],
          authLevel: 'anonymous',
          extraInputs: [connection],
          handler: async (request, context) => {
              return { body: JSON.stringify(context.extraInputs.get('connection')) };
          },
      });
      
  5. Skapa en message funktion för att sända klientmeddelanden via tjänsten.

    func new -n message -t HttpTrigger
    
    • Uppdatera src/functions/message.js och kopiera följande koder.
      const { app, output, trigger } = require('@azure/functions');
      
      const wpsMsg = output.generic({
          type: 'webPubSub',
          name: 'actions',
          hub: 'simplechat',
      });
      
      const wpsTrigger = trigger.generic({
          type: 'webPubSubTrigger',
          name: 'request',
          hub: 'simplechat',
          eventName: 'message',
          eventType: 'user'
      });
      
      app.generic('message', {
          trigger: wpsTrigger,
          extraOutputs: [wpsMsg],
          handler: async (request, context) => {
              context.extraOutputs.set(wpsMsg, [{
                  "actionName": "sendToAll",
                  "data": `[${context.triggerMetadata.connectionContext.userId}] ${request.data}`,
                  "dataType": request.dataType
              }]);
      
              return {
                  data: "[SYSTEM] ack.",
                  dataType: "text",
              };
          }
      });
      
  6. Lägg till klientens enstaka sida index.html i projektets rotmapp och kopiera innehåll.

    <html>
      <body>
        <h1>Azure Web PubSub Serverless Chat App</h1>
        <div id="login"></div>
        <p></p>
        <input id="message" placeholder="Type to chat..." />
        <div id="messages"></div>
        <script>
          (async function () {
            let authenticated = window.location.href.includes(
              "?authenticated=true"
            );
            if (!authenticated) {
              // auth
              let login = document.querySelector("#login");
              let link = document.createElement("a");
              link.href = `${window.location.origin}/.auth/login/aad?post_login_redirect_url=/api/index?authenticated=true`;
              link.text = "login";
              login.appendChild(link);
            } else {
              // negotiate
              let messages = document.querySelector("#messages");
              let res = await fetch(`${window.location.origin}/api/negotiate`, {
                credentials: "include",
              });
              let url = await res.json();
              // connect
              let ws = new WebSocket(url.url);
              ws.onopen = () => console.log("connected");
              ws.onmessage = (event) => {
                let m = document.createElement("p");
                m.innerText = event.data;
                messages.appendChild(m);
              };
              let message = document.querySelector("#message");
              message.addEventListener("keypress", (e) => {
                if (e.charCode !== 13) return;
                ws.send(message.value);
                message.value = "";
              });
            }
          })();
        </script>
      </body>
    </html>
    

Skapa och distribuera Azure-funktionsappen

Innan du kan distribuera funktionskoden till Azure måste du skapa tre resurser:

  • En resursgrupp, som är en logisk container för relaterade resurser.
  • Ett lagringskonto som används för att underhålla tillstånd och annan information om dina funktioner.
  • En funktionsapp som tillhandahåller miljön för att köra funktionskoden. En funktionsapp mappar till ditt lokala funktionsprojekt och låter dig gruppera funktioner som en logisk enhet för enklare hantering, distribution och delning av resurser.

Använd följande kommandon för att skapa dessa objekt.

  1. Om du inte redan har gjort det loggar du in på Azure:

    az login
    
  2. Skapa en resursgrupp eller så kan du hoppa över genom att återanvända en av Azure Web PubSub-tjänsten:

    az group create -n WebPubSubFunction -l <REGION>
    
  3. Skapa ett allmänt lagringskonto i din resursgrupp och region:

    az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
    
  4. Skapa funktionsappen i Azure:

    az functionapp create --resource-group WebPubSubFunction --consumption-plan-location <REGION> --runtime node --runtime-version 18 --functions-version 4 --name <FUNCIONAPP_NAME> --storage-account <STORAGE_NAME>
    

    Anmärkning

    Kontrollera dokumentationen för Azure Functions-körningsversioner för att ange --runtime-version parametern till det värde som stöds.

  5. Distribuera funktionsprojektet till Azure:

    När du har skapat funktionsappen i Azure är du nu redo att distribuera ditt lokala funktionsprojekt med hjälp av publiceringskommandot func azure functionapp .

    func azure functionapp publish <FUNCIONAPP_NAME>
    
  6. Konfigurera WebPubSubConnectionString för funktionsappen:

    Råa anslutningssträng visas endast i den här artikeln i demonstrationssyfte. Skydda alltid dina åtkomstnycklar i produktionsmiljöer. Använd Azure Key Vault för att hantera och rotera dina nycklar säkert och säkra din anslutning med WebPubSubServiceClient.

    Leta först upp din Web PubSub-resurs från Azure-portalen och kopiera ut anslutningssträngen under Nycklar. Gå sedan till Funktionsappsinställningar i Azure Portal –>Inställningar –>Miljövariabler. Och lägg till ett nytt objekt under Appinställningar, med namnet WebPubSubConnectionString och med värdet som är din Web PubSub-resursanslutningssträng.

Konfigurera tjänsten Web PubSub Event Handler

I det här exemplet använder WebPubSubTrigger vi för att lyssna på uppströmsbegäranden i tjänsten. Web PubSub behöver därför känna till funktionens slutpunktsinformation för att kunna skicka målklientbegäranden. Och Azure-funktionsappen kräver en systemnyckel för säkerhet för tilläggsspecifika webhookmetoder. I föregående steg, efter att vi distribuerade funktionsappen med message funktioner, kan vi hämta systemnyckeln.

Gå till Azure-portalen –> Hitta funktionsappresursen ->Appnycklar ->Systemnycklar ->webpubsub_extension. Kopiera ut värdet som <APP_KEY>.

Skärmbild av hämta funktionssystemnycklar.

Ange Event Handler i Azure Web PubSub-tjänsten. Gå till Azure-portalen –> Hitta din Web PubSub-resurs –>Inställningar. Lägg till en ny hubbinställningsmappning till den funktion som används. Ersätt <FUNCTIONAPP_NAME> och <APP_KEY> med dina.

  • Hubbnamn: simplechat
  • URL-mall: https://<FUNCTIONAPP_NAME>.azurewebsites.net/runtime/webhooks/webpubsub?code=<APP_KEY>
  • Användarhändelsemönster: *
  • Systemhändelser: -(Du behöver inte konfigurera i det här exemplet)

Skärmbild av hur du ställer in händelsehanteraren.

Konfigurera för att aktivera klientautentisering

Gå till Azure-portalen –> Hitta funktionsappresursen ->Autentisering. Klicka på Add identity provider. Ställ in autentiseringsinställningar för App ServiceTillåt oautentiserad åtkomst, så att klientindexsidan kan besökas av anonyma användare innan du omdirigerar till autentisering. Spara sedan.

Här väljer vi Microsoft som identifieringsleverantör, som använder x-ms-client-principal-name som userId i negotiate funktion. Dessutom kan du konfigurera andra identitetsleverantörer genom att följa länkarna, och glöm inte att uppdatera userId-värdet i negotiate-funktionen i enlighet med detta.

Prova programmet

Nu kan du testa sidan från funktionsappen: https://<FUNCTIONAPP_NAME>.azurewebsites.net/api/index. Se ögonblicksbild.

  1. Klicka på login för att autentisera dig.
  2. Skriv meddelandet i indatarutan för att chatta.

I meddelandefunktionen sänder vi uppringarens meddelande till alla klienter och returnerar anroparen med meddelandet [SYSTEM] ack. Så vi kan veta i exempel på chattögonblicksbild att de första fyra meddelandena kommer från den aktuella klienten och att de två sista meddelandena kommer från en annan klient.

Skärmbild av chattexempel.

Rensa resurser

Om du inte kommer att fortsätta att använda den här appen tar du bort alla resurser som skapats av det här dokumentet med följande steg så att du inte debiteras några avgifter:

  1. Välj Resursgrupper i Azure Portal längst till vänster och välj sedan den resursgrupp du skapat. Du kan använda sökrutan för att hitta resursgruppen med dess namn i stället.

  2. I fönstret som öppnas väljer du resursgruppen och väljer sedan Ta bort resursgrupp.

  3. I det nya fönstret skriver du namnet på resursgruppen som ska tas bort och väljer sedan Ta bort.

Nästa steg

I den här snabbstarten har du lärt dig hur du kör ett serverlöst chattprogram. Nu kan du börja skapa ett eget program.