Tutoriel : Créer une application de conversation serverless avec Azure Functions et le service Azure Web PubSub

Le service Azure Web PubSub vous aide à créer facilement des applications web de messagerie en temps réel avec des WebSockets et le modèle publication-abonnement. Azure Functions est une plateforme serverless qui vous permet d’exécuter votre code sans gérer d’infrastructures. Dans ce démarrage rapide, découvrez comment utiliser le service Azure Web PubSub et Azure Functions pour générer une application serverless avec une messagerie en temps réel et le modèle publication-abonnement.

Dans ce tutoriel, vous allez apprendre à :

  • Créer une application de conversation serverless
  • Utiliser des liaisons de déclencheur et de sortie de fonction Web PubSub
  • Déployer la fonction sur l’application de fonction Azure
  • Configurer l’authentification Azure
  • Configurer le gestionnaire d’événements Web PubSub pour acheminer les événements et les messages vers l’application

Prérequis

Si vous n’avez pas d’abonnement Azure, créez un compte gratuit Azure avant de commencer.

Connexion à Azure

Connectez-vous au portail Azure sur https://portal.azure.com/ avec votre compte Azure.

Créer une instance de service Azure Web PubSub

Votre application se connectera à l’instance de service Web PubSub dans Azure.

  1. Cliquez sur le bouton Nouveau dans le coin supérieur gauche du portail Azure. À l’écran Nouveau, saisissez Web PubSub dans la zone de recherche et appuyez sur Entrée. (Vous pouvez également effectuer une recherche dans Azure Web PubSub à partir de la catégorie Web.)

    Capture d’écran d’une recherche dans Azure Web PubSub depuis le portail.

  2. Sélectionnez Web PubSub dans les résultats de la recherche, puis Créer.

  3. Entrez les paramètres suivants.

    Paramètre Valeur suggérée Description
    Nom de la ressource Nom globalement unique Nom unique au monde qui identifie votre nouvelle instance de service Web PubSub. Les caractères valides sont a-z, A-Z, 0-9 et -.
    Abonnement Votre abonnement Abonnement Azure sous lequel cette instance de service Web PubSub est créée.
    Groupe de ressources myResourceGroup Le nom du nouveau groupe de ressources dans lequel créer l’instance de service Web PubSub.
    Lieu USA Ouest Sélectionnez une région proche de chez vous.
    Niveau tarifaire Gratuit Vous pouvez d’abord essayer le service Azure Web PubSub gratuitement. En savoir plus sur les niveaux tarifaires du service Azure Web PubSub
    Nombre d’unité - Le nombre d’unité spécifie le nombre de connexions que votre instance de service Web PubSub peut accepter. Chaque unité prend en charge 1 000 connexions simultanées au maximum. Ceci n’est configurable que dans le niveau Standard.

    Capture d’écran illustrant la création d’une instance Azure Web PubSub dans le portail.

  4. Sélectionnez Créer pour commencer le déploiement de l’instance de service Web PubSub.

Créer les fonctions

  1. Vérifiez qu’Azure Functions Core Tools est installé. Puis créez un répertoire vide pour le projet. Exécutez la commande sous ce répertoire de travail.

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

    Confirmez et mettez à jour l’extensionBundle de host.json à la version 4.* ou ultérieure pour obtenir la prise en charge de Web PubSub.

    {
      "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.*, 5.0.0)"
      }
    }
    
  3. Créez une fonction index pour lire et héberger une page web statique pour les clients.

    func new -n index -t HttpTrigger
    
    • Mettez à jour src/functions/index.js et copiez les codes suivants.
      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. Créez une fonction negotiate pour aider les clients à obtenir l’URL de connexion au service avec le jeton d’accès.

    func new -n negotiate -t HttpTrigger
    

    Remarque

    Dans cet exemple, nous utilisons l’en-tête x-ms-client-principal-name d’identité utilisateur Microsoft Entra ID pour récupérer userId. Cela ne fonctionnera pas dans une fonction locale. Vous pouvez l’utiliser vide ou le modifier de manière à obtenir ou générer userId lorsque vous travaillez en local. Par exemple, permettez au client de taper un nom d’utilisateur et de le passer dans une requête comme ?user={$username} lorsque vous appelez la fonction negotiate pour obtenir l’URL de connexion du service. Dans la fonction negotiate, définissez userId sur la valeur {query.user}.

    • Mettez à jour src/functions/negotiate et copiez les codes suivants.
      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. Créez une fonction message pour diffuser des messages clients via le service.

    func new -n message -t HttpTrigger
    
    • Mettez à jour src/functions/message.js et copiez les codes suivants.
      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. Ajoutez la page unique du client index.html dans le dossier racine du projet et copiez le contenu.

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

Créer et déployer l’application de fonction Azure

Avant de déployer le code de votre fonction dans Azure, vous devez créer trois ressources :

  • Un groupe de ressources, qui est un conteneur logique pour les ressources associées.
  • Un compte de stockage, qui sert à conserver l’état et d’autres informations sur vos fonctions.
  • Une application de fonction, qui fournit l’environnement d’exécution de votre code de fonction. Une application de fonction est mappée à votre projet de fonction local. Elle vous permet de regrouper les fonctions en tant qu’unité logique pour faciliter la gestion, le déploiement et le partage des ressources.

Utilisez les commandes suivantes pour créer ces éléments.

  1. Si vous ne l’avez pas déjà fait, connectez-vous à Azure :

    az login
    
  2. Créez un groupe de ressources, ou vous pouvez ignorer cette étape en réutilisant l’un des services Azure Web PubSub :

    az group create -n WebPubSubFunction -l <REGION>
    
  3. Créez un compte de stockage universel dans votre groupe de ressources et votre région :

    az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
    
  4. Créer l’application de fonction dans 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>
    

    Notes

    Consultez la documentation des versions d'exécution d'Azure Functions pour définir le paramètre --runtime-version à une valeur prise en charge.

  5. Déployez le projet de fonction sur Azure :

    Après avoir créé votre application de fonction dans Azure, vous êtes prêt à déployer votre projet Functions local à l’aide de la commande func azure functionapp publish.

    func azure functionapp publish <FUNCIONAPP_NAME>
    
  6. Configurez WebPubSubConnectionString pour l’application de fonction :

    En premier lieu, recherchez votre ressource Web PubSub dans le portail Azure, et copiez la chaîne de connexion sous Clés. Ensuite, accédez aux paramètres de l’application de fonction dans Portail Azure ->Paramètres ->Configuration. Ajoutez un nouvel élément sous Paramètres de l’application, avec le nom égal à WebPubSubConnectionString, et la valeur correspondant à la chaîne de connexion de votre ressource Web PubSub.

Configurer le Event Handler du service Web PubSub

Dans cet exemple, nous utilisons WebPubSubTrigger pour écouter les demandes de service en amont. Web PubSub doit donc connaître les informations de point de terminaison de la fonction pour envoyer des demandes de clients cibles. De plus, Azure Function App nécessite une clé système pour la sécurité des méthodes de webhook relatives aux extensions. Dans l’étape précédente, après avoir déployé l’application de fonction avec les fonctions message, nous avons pu obtenir la clé système.

Accédez à Portail Azure -> recherchez votre ressource d’application de fonction ->Clés d’application ->Clés système ->webpubsub_extension. Copiez la valeur au format suivant : <APP_KEY>.

Capture d’écran des clés système d’obtention de la clé.

Définissez Event Handler dans le service Azure Web PubSub. Accédez à Portail Azure -> recherchez votre ressource Web PubSub ->Paramètres. Ajoutez un nouveau mappage de paramètres de hub à la fonction en cours d’utilisation comme indiqué. Remplacez <FUNCTIONAPP_NAME> et <APP_KEY> par vos propres valeurs.

  • Nom du hub : simplechat
  • Modèle d’URL : https://<FUNCTIONAPP_NAME>.azurewebsites.net/runtime/webhooks/webpubsub?code=<APP_KEY>
  • Modèle d’événement utilisateur : *
  • Événements système : (inutile de les configurer dans cet exemple)

Capture d’écran de la définition du gestionnaire d’événements.

Configurer l’activation de l’authentification client

Accédez à Portail Azure -> recherchez votre ressource d’application de fonction ->Authentification. Cliquez sur Add identity provider. Configurez Paramètres d’authentification App Service sur Autoriser l’accès non authentifié, de manière à permettre aux utilisateurs anonymes de visiter la page d’index du client avant de les rediriger pour l’authentification. Enregistrez.

Ici, nous choisissons Microsoft comme fournisseur d’identification, lequel utilise x-ms-client-principal-name comme userId dans la fonction negotiate. Vous pouvez configurer d’autres fournisseurs d’identité en suivant les liens. N’oubliez pas de mettre à jour la valeur userId en conséquence dans la fonction negotiate.

Tester l’application

Maintenant, vous pouvez tester votre page à partir de votre application de fonction https://<FUNCTIONAPP_NAME>.azurewebsites.net/api/index. Voir la capture d’écran.

  1. Cliquez sur login pour vous authentifier.
  2. Tapez un message dans la zone de saisie pour commencer la conversation.

Dans la fonction de message, nous diffusons le message de l’appelant vers tous les clients, puis retourner le message [SYSTEM] ack à l’appelant. Nous pouvons donc savoir d’après la capture d’écran de l’exemple de conversation que les quatre premiers messages proviennent du client actuel et que les deux derniers messages proviennent d’un autre client.

Capture d’écran de l’exemple de conversation.

Nettoyer les ressources

Si vous ne pensez pas continuer à utiliser cette application, supprimez toutes les ressources créées dans le cadre de cette documentation en procédant de la façon suivante afin d’éviter des frais :

  1. Dans le portail Azure, sélectionnez Groupes de ressources tout à gauche, puis sélectionnez le groupe de ressources que vous avez créé. Si vous préférez, vous pouvez utiliser la zone de recherche pour trouver le groupe de ressources grâce à son nom.

  2. Dans la fenêtre qui s’ouvre, sélectionnez le groupe de ressources, puis sélectionnez Supprimer le groupe de ressources.

  3. Dans la nouvelle fenêtre, tapez le nom du groupe de ressources à supprimer, puis sélectionnez Supprimer.

Étapes suivantes

Dans ce démarrage rapide, vous avez appris à exécuter une application de conversation serverless. À présent, vous pouvez commencer à créer votre propre application.