Zelfstudie: Een serverloze realtime chat-app maken met Azure Functions en de Azure Web PubSub-service

Met de Azure Web PubSub-service kunt u eenvoudig realtime webtoepassingen voor berichten bouwen met behulp van WebSockets en het patroon publish-subscribe. Azure Functions is een serverloos platform waarmee u code kunt uitvoeren zonder een infrastructuur te beheren. In deze zelfstudie leert u hoe u de Azure Web PubSub-service en Azure Functions gebruikt om een serverloze toepassing te bouwen met realtime berichten en het patroon publish-subscribe.

In deze zelfstudie leert u het volgende:

  • Een serverloze realtime chat-app bouwen
  • Werken met web PubSub-functietriggerbindingen en uitvoerbindingen
  • De functie implementeren in de Azure-functie-app
  • Azure-verificatie configureren
  • Web PubSub Event Handler configureren om gebeurtenissen en berichten naar de toepassing te routeren

Vereisten

  • Een code-editor zoals Visual Studio Code

  • Node.js versie 18.x of hoger.

    Notitie

    Zie de documentatie over runtimeversies van Azure Functions voor meer informatie over de ondersteunde versies van Node.js.

  • Azure Functions Core Tools (v4 of hoger) om Azure Function-apps lokaal uit te voeren en te implementeren in Azure.

  • De Azure CLI voor het beheren van Azure-resources.

Als u geen Azure-abonnement hebt, kunt u een gratis Azure-account maken voordat u begint.

Aanmelden bij Azure

Meld u met uw Azure-account aan bij de Azure-portal op https://portal.azure.com/.

Een Azure Web PubSub-service-exemplaar maken

Uw toepassing maakt verbinding met een Web PubSub-service-exemplaar in Azure.

  1. Selecteer de knop Nieuw in de linkerbovenhoek van Azure Portal. Typ In het scherm Nieuw Web PubSub in het zoekvak en druk op Enter. (U kunt ook zoeken in de Azure Web PubSub vanuit de Web categorie.)

    Schermopname van het doorzoeken van de Azure Web PubSub in de portal.

  2. Selecteer Web PubSub in de zoekresultaten en selecteer Vervolgens Maken.

  3. Voer de volgende instellingen in.

    Instelling Voorgestelde waarde Beschrijving
    Resourcenaam Wereldwijd unieke naam De wereldwijd unieke naam waarmee uw nieuwe exemplaar van de Web PubSub-service wordt geïdentificeerd. Geldige tekens zijn a-z, A-Zen 0-9-.
    Abonnement Uw abonnement Het Azure-abonnement waaronder dit nieuwe exemplaar van de Web PubSub-service wordt gemaakt.
    Resourcegroep myResourceGroup Naam voor de nieuwe resourcegroep waarin u uw Web PubSub-service-exemplaar wilt maken.
    Location VS - west Kies een regio bij u in de buurt.
    Prijscategorie Gratis U kunt de Azure Web PubSub-service eerst gratis uitproberen. Meer informatie over de prijscategorieën van de Azure Web PubSub-service
    Aantal eenheden - Aantal eenheden geeft aan hoeveel verbindingen uw Exemplaar van de Web PubSub-service kan accepteren. Elke eenheid ondersteunt maximaal 1000 gelijktijdige verbindingen. Dit kan alleen worden geconfigureerd in de Standard-laag.

    Schermopname van het maken van het Azure Web PubSub-exemplaar in de portal.

  4. Selecteer Maken om te beginnen met het implementeren van het Web PubSub-service-exemplaar.

De functies maken

  1. Zorg ervoor dat Azure Functions Core Tools is geïnstalleerd. Maak vervolgens een lege map voor het project. Voer de opdracht uit onder deze werkmap.

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

    Bevestig en werk host.jsonextensionBundle bij naar versie 4.* of hoger om ondersteuning voor Web PubSub te krijgen.

    {
      "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.*, 5.0.0)"
      }
    }
    
  3. Maak een index functie voor het lezen en hosten van een statische webpagina voor clients.

    func new -n index -t HttpTrigger
    
    • Werk src/functions/index.js de volgende codes bij en kopieer deze.
      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. Maak een negotiate functie om clients te helpen serviceverbindings-URL met toegangstoken op te halen.

    func new -n negotiate -t HttpTrigger
    

    Notitie

    In dit voorbeeld gebruiken we de header van de gebruikersidentiteit x-ms-client-principal-name van Microsoft Entra ID om op te halenuserId. En dit werkt niet in een lokale functie. U kunt het leeg maken of wijzigen in andere manieren om te verkrijgen of te genereren userId wanneer u lokaal speelt. Laat de client bijvoorbeeld een gebruikersnaam typen en deze doorgeven in een query, bijvoorbeeld ?user={$username} wanneer de aanroepfunctie negotiate om de serviceverbindings-URL op te halen. En stel in de negotiate functie userId een waarde {query.user}in.

    • Werk src/functions/negotiate de volgende codes bij en kopieer deze.
      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. Maak een message functie voor het uitzenden van clientberichten via de service.

    func new -n message -t HttpTrigger
    
    • Werk src/functions/message.js de volgende codes bij en kopieer deze.
      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. Voeg de client met één pagina index.html toe in de hoofdmap van het project en kopieer inhoud.

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

De Azure-functie-app maken en implementeren

Voordat u uw functiecode kunt implementeren in Azure, moet u drie resources maken:

  • Een resourcegroep, wat een logische container is voor gerelateerde resources.
  • Een opslagaccount dat wordt gebruikt voor het onderhouden van status en andere informatie over uw functies.
  • Een functie-app, die de omgeving biedt voor het uitvoeren van uw functiecode. Een functie-app wordt toegewezen aan uw lokale functieproject en stelt u in staat om functies te groeperen als een logische eenheid voor eenvoudiger beheer, implementatie en delen van resources.

Gebruik de volgende opdrachten om deze items te maken.

  1. Als u dit nog niet hebt gedaan, meldt u zich aan bij Azure:

    az login
    
  2. Maak een resourcegroep of u kunt dit overslaan door de Azure Web PubSub-service opnieuw te gebruiken:

    az group create -n WebPubSubFunction -l <REGION>
    
  3. Maak een algemeen opslagaccount in de resourcegroep en regio:

    az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
    
  4. De functie-app maken in 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>
    

    Notitie

    Raadpleeg de documentatie over runtimeversies van Azure Functions om de parameter in te stellen --runtime-version op ondersteunde waarde.

  5. Het functieproject implementeren in Azure:

    Nadat u uw functie-app in Azure hebt gemaakt, bent u nu klaar om uw lokale functions-project te implementeren met behulp van de func azure functionapp publish-opdracht .

    func azure functionapp publish <FUNCIONAPP_NAME>
    
  6. Configureer de WebPubSubConnectionString functie-app:

    Zoek eerst uw Web PubSub-resource uit de Azure-portal en kopieer de verbindingsreeks onder Sleutels. Navigeer vervolgens naar instellingen voor functie-apps in Azure Portal ->Instellingen ->Configuration. En voeg een nieuw item toe onder Toepassingsinstellingen, waarbij de naam gelijk is WebPubSubConnectionString aan en de waarde uw Web PubSub-resource is verbindingsreeks.

De Web PubSub-service configureren Event Handler

In dit voorbeeld wordt gebruikgemaakt WebPubSubTrigger van het luisteren naar upstream-aanvragen van services. Web PubSub moet dus weten wat de eindpuntgegevens van de functie zijn om doelclientaanvragen te kunnen verzenden. En Azure Function App vereist een systeemsleutel voor beveiliging met betrekking tot extensiespecifieke webhookmethoden. In de vorige stap nadat we de functie-app met message functies hebben geïmplementeerd, kunnen we de systeemsleutel ophalen.

Ga naar Azure Portal -> Zoek uw functie-app-resource ->App-sleutels ->Systeemsleutels ->webpubsub_extension. Kopieer de waarde als <APP_KEY>.

Schermopname van functiesysteemsleutels ophalen.

Ingesteld Event Handler in de Azure Web PubSub-service. Ga naar Azure Portal :> zoek uw Web PubSub-resource ->Instellingen. Voeg een nieuwe hubinstellingentoewijzing toe aan de ene functie die wordt gebruikt. Vervang de <FUNCTIONAPP_NAME> en <APP_KEY> de jouwe.

  • Hubnaam: simplechat
  • URL-sjabloon: https://< FUNCTIONAPP_NAME.azurewebsites.net/runtime/webhooks/webpubsub?code>=<APP_KEY>
  • Gebruikers gebeurtenispatroon: *
  • Systeemgebeurtenissen: -(Niet nodig om in dit voorbeeld te configureren)

Schermopname van het instellen van de gebeurtenis-handler.

Configureren om clientverificatie in te schakelen

Ga naar Azure Portal -> Zoek uw functie-app-resource -> Verificatie. Klik op Add identity provider. Stel app Service-verificatie-instellingen in op Niet-geverifieerde toegang toestaan, zodat uw clientindexpagina kan worden bezocht door anonieme gebruikers voordat ze worden omgeleid naar verificatie. Selecteer vervolgens Opslaan.

Hier kiezen Microsoft we als identificatieprovider, die wordt gebruikt x-ms-client-principal-name als userId in de negotiate functie. Bovendien kunt u andere id-providers configureren door de koppelingen te volgen en vergeet niet de userId waarde in negotiate functie dienovereenkomstig bij te werken.

De toepassing uitproberen

Nu kunt u uw pagina testen vanuit uw functie-app: https://<FUNCTIONAPP_NAME>.azurewebsites.net/api/index. Zie momentopname.

  1. Klik login hier om uzelf te autoreren.
  2. Typ een bericht in het invoervak om te chatten.

In de berichtfunctie verzenden we het bericht van de beller naar alle clients en retourneren we de beller met bericht [SYSTEM] ack. Zodat we kunnen weten in een voorbeeld van een chatmomentopname, zijn de eerste vier berichten afkomstig van de huidige client en de laatste twee berichten zijn van een andere client.

Schermopname van een chatvoorbeeld.

Resources opschonen

Als u deze app niet wilt blijven gebruiken, verwijdert u alle resources die door dit document zijn gemaakt met de volgende stappen, zodat er geen kosten in rekening worden gebracht:

  1. Selecteer links in de Azure-portal de optie Resourcegroepen en selecteer vervolgens de resourcegroep die u hebt gemaakt. U kunt het zoekvak gebruiken om in plaats daarvan de resourcegroep op naam te vinden.

  2. Selecteer in het venster dat wordt geopend de resourcegroep en selecteer vervolgens Resourcegroep verwijderen.

  3. Typ in het nieuwe venster de naam van de resourcegroep die u wilt verwijderen en selecteer vervolgens Verwijderen.

Volgende stappen

In deze quickstart hebt u geleerd hoe u een serverloze chattoepassing uitvoert. U kunt nu beginnen met het bouwen van uw eigen toepassing.