Condividi tramite


Esercitazione: Creare un'app di chat in tempo reale serverless con Funzioni di Azure e il servizio Azure Web PubSub

Il servizio Azure Web PubSub consente di creare facilmente applicazioni Web di messaggistica in tempo reale tramite WebSocket e il modello pubblicazione-sottoscrizione. Funzioni di Azure è una piattaforma serverless che consente di eseguire il codice senza gestire alcuna infrastruttura. Questa esercitazione illustra come usare il servizio Azure Web PubSub e Funzioni di Azure per creare un'applicazione serverless con messaggistica in tempo reale e il modello pubblicazione-sottoscrizione.

In questa esercitazione apprenderai a:

  • Creare un'app di chat in tempo reale serverless
  • Usare associazioni di trigger e output della funzione Web PubSub
  • Distribuire la funzione nell'app per le funzioni di Azure
  • Configurare l'autenticazione di Azure
  • Configurare il gestore eventi di Web PubSub per instradare eventi e messaggi all'applicazione

Prerequisiti

Se non si ha una sottoscrizione di Azure, creare un account Azure gratuito prima di iniziare.

Accedere ad Azure

Accedere al portale di Azure all'indirizzo https://portal.azure.com/ con il proprio account Azure.

Creare un'istanza del servizio Azure Web PubSub

L'applicazione si connette a un'istanza del servizio Web PubSub in Azure.

  1. Selezionare il pulsante Nuovo nell'angolo superiore sinistro del portale di Azure. Nella nuova schermata, digitare Web PubSub nella casella di ricerca e premere Invio. (È anche possibile eseguire una ricerca in Azure Web PubSub dalla categoria Web.)

    Screenshot della ricerca in Azure Web PubSub nel portale.

  2. Nei risultati della ricerca, selezionare Web PubSub e quindi fare clic su Crea.

  3. Immettere le impostazioni seguenti.

    Impostazione Valore suggerito Descrizione
    Nome risorsa Nome globalmente univoco Nome univoco globale che identifica la nuova istanza del servizio Web PubSub. I caratteri validi sono a-z, A-Z, 0-9 e -.
    Abbonamento Sottoscrizione in uso La sottoscrizione Azure in cui verrà creata questa nuova istanza del servizio Web PubSub.
    Gruppo di risorse myResourceGroup Nome del nuovo gruppo di risorse in cui creare l'istanza del servizio Web PubSub.
    Location Stati Uniti occidentali Scegliere un'area nelle vicinanze.
    Piano tariffario Gratuito È possibile eseguire dapprima una prova gratuita del servizio Azure Web PubSub. Altre informazioni sul piano tariffario del servizio Azure Web PubSub
    Unità: conteggio - Il numero di unità specifica il numero di connessioni che può essere accettato dall'istanza del servizio Web PubSub. Ogni unità supporta al massimo 1.000 connessioni simultanee. È configurabili solo nel livello Standard.

    Screenshot della creazione dell'istanza Azure Web PubSub nel portale.

  4. Selezionare Crea per iniziare la distribuzione dell'istanza del servizio Web PubSub.

Creare le funzioni

  1. Assicurarsi di avere installato Azure Functions Core Tools. Creare quindi una directory vuota per il progetto. Eseguire il comando in questa directory di lavoro.

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

    Confermare e aggiornare extensionBundle di host.json alla versione 4.* o successive per ottenere il supporto di Web PubSub.

    {
      "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.*, 5.0.0)"
      }
    }
    
  3. Creare una funzione index per leggere e ospitare una pagina Web statica per i client.

    func new -n index -t HttpTrigger
    
    • Aggiornare src/functions/index.js e copiare i codici seguenti.
      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. Creare una funzione negotiate per consentire ai client di ottenere l'URL di connessione al servizio con il token di accesso.

    func new -n negotiate -t HttpTrigger
    

    Nota

    In questo esempio viene usata l'intestazione dell'identità utente x-ms-client-principal-name di Microsoft Entra ID per recuperare userId. Questa opzione non è disponibile con una funzione locale. È possibile lasciare il campo vuoto o usare altri modi per ottenere o generare userId durante la riproduzione in locale. Ad esempio, consentire al client di digitare un nome utente e passarlo in query come ?user={$username} quando si chiama la funzione negotiate per ottenere l'URL di connessione al servizio. Nella funzione negotiate, impostare userId con valore {query.user}.

    • Aggiornare src/functions/negotiate e copiare i codici seguenti.
      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. Creare una funzione message per trasmettere i messaggi client tramite il servizio.

    func new -n message -t HttpTrigger
    
    • Aggiornare src/functions/message.js e copiare i codici seguenti.
      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. Aggiungere il client a pagina singola index.html nella cartella radice del progetto e copiare il contenuto.

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

Creare e distribuire l'app per le funzioni di Azure

Prima di distribuire il codice della funzione in Azure, è necessario creare tre risorse:

  • Un gruppo di risorse, ovvero un contenitore logico di risorse correlate.
  • Un account di archiviazione, usato per mantenere lo stato e altre informazioni sulle funzioni.
  • Un'app per le funzioni, che fornisce l'ambiente per l'esecuzione del codice della funzione. Un'app per le funzioni si collega al progetto di funzioni locale e consente di raggruppare le funzioni come un'unità logica per semplificare la gestione, la distribuzione e la condivisione di risorse.

Usare i comandi seguenti per creare questi elementi.

  1. Se non è già stato fatto, accedere ad Azure:

    az login
    
  2. Creare un gruppo di risorse oppure ignorare questo passaggio e riutilizzare il gruppo del servizio Azure Web PubSub:

    az group create -n WebPubSubFunction -l <REGION>
    
  3. Creare un account di archiviazione per utilizzo generico nel gruppo di risorse e nell'area:

    az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
    
  4. Creare l'app per le funzioni 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>
    

    Nota

    Controllare la documentazione delle versioni di runtime di Funzioni di Azure per impostare il parametro--runtime-version sul valore supportato.

  5. Distribuire il progetto di funzioni in Azure:

    Dopo aver creato l'app per le funzioni in Azure, è ora possibile distribuire il progetto di funzioni locale usando il comando func azure functionapp publish.

    func azure functionapp publish <FUNCIONAPP_NAME>
    
  6. Configurare WebPubSubConnectionString per l'app per le funzioni:

    Prima di tutto, trovare la risorsa Web PubSub nel portale di Azure e copiare la stringa di connessione in Chiavi. Passare quindi a Impostazioni dell'app per le funzioni in Portale di Azure ->Impostazioni - >Configurazione. Aggiungere un nuovo elemento in Impostazioni applicazione, con nome WebPubSubConnectionString e per valore la stringa di connessione della risorsa Web PubSub.

Configurare il Event Handler del servizio Web PubSub

In questo esempio viene usato WebPubSubTrigger per ascoltare le richieste upstream del servizio. Web PubSub deve disporre di informazioni sull'endpoint della funzione per inviare richieste client di destinazione. Inoltre, l'app per le funzioni di Azure richiede una chiave di sistema per la sicurezza dei metodi webhook specifici dell'estensione. Nel passaggio precedente, dopo aver distribuito l'app per le funzioni con le funzioni di message, è possibile ottenere la chiave di sistema.

Andare a Portale di Azure -> Trovare la risorsa dell'app per le funzioni ->Chiavi dell'app ->Chiavi di sistema ->webpubsub_extension. Copiare il valore come <APP_KEY>.

Screenshot delle chiavi di sistema della funzione get.

Impostare Event Handler nel servizio Azure Web PubSub. Andare a Portale di Azure -> Trovare la risorsa Web PubSub - >Impostazioni. Aggiungere un nuovo mapping delle impostazioni dell'hub alla funzione in uso. Sostituire i valori <FUNCTIONAPP_NAME> e <APP_KEY> con quelli personalizzati.

  • Nome hub: simplechat
  • Modello di URL: https://<FUNCTIONAPP_NAME>.azurewebsites.net/runtime/webhooks/webpubsub?code=<APP_KEY>
  • Modello di eventi utente: *
  • Eventi di sistema: - (Nessuna configurazione necessaria in questo esempio)

Screenshot dell'impostazione del gestore eventi.

Configurare l'abilitazione dell'autenticazione client

Andare a Portale di Azure -> Trovare la risorsa dell'app per le funzioni ->Autenticazione. Fare clic su Add identity provider. Configurare le impostazioni di autenticazione del servizio app su Consenti accesso non autenticato, in modo che la pagina dell'indice client possa essere visitata dagli utenti anonimi prima del reindirizzamento per l'autenticazione. Quindi fai clic su Salva.

In questo caso si sceglie Microsoft come provider di identificazione, che usa x-ms-client-principal-name come userId nella funzione di negotiate. È inoltre possibile configurare altri provider di identità seguendo i collegamenti, senza dimenticare di aggiornare di conseguenza il valore userId nella funzione di negotiate.

Provare l'applicazione

A questo punto è possibile testare la pagina dall'app per le funzioni: https://<FUNCTIONAPP_NAME>.azurewebsites.net/api/index. Vedere lo snapshot.

  1. Fare clic su login per autenticarsi.
  2. Digitare un messaggio nella casella di input per chattare.

Con la funzione di messaggistica, il messaggio del chiamante viene trasmesso a tutti i client e il messaggio [SYSTEM] ack viene restituito al chiamante. Lo snapshot della chat di esempio mostra che i primi quattro messaggi provengono dal client corrente e gli ultimi due da un altro client.

Screenshot di un esempio di chat.

Pulire le risorse

Se non si intende continuare a usare l'app, eliminare tutte le risorse create tramite questo documento eseguendo i passaggi seguenti, per evitare qualsiasi addebito:

  1. Nel portale di Azure selezionare Gruppi di risorse all'estrema sinistra e quindi selezionare il gruppo di risorse creato. In alternativa, è possibile usare la casella di ricerca per trovare il gruppo di risorse in base al nome.

  2. Nella finestra che si apre, selezionare il gruppo di risorse e quindi selezionare Elimina gruppo di risorse.

  3. Nella finestra successiva, digitare il nome del gruppo di risorse da eliminare e quindi selezionare Elimina.

Passaggi successivi

In questa guida introduttiva si è appreso come eseguire un'applicazione di chat serverless. Ora è possibile iniziare a creare un'applicazione personalizzata.