Compartir a través de


Tutorial: Creación de una aplicación de chat en tiempo real sin servidor con Azure Functions y el servicio Azure Web PubSub

El servicio Azure Web PubSub le ayuda a crear aplicaciones web de mensajería en tiempo real mediante WebSockets y el patrón de publicación y suscripción fácilmente. Azure Functions es una plataforma sin servidor que le permite ejecutar el código sin tener que administrar ninguna infraestructura. En este tutorial, aprenderá a usar el servicio Azure Web PubSub y Azure Functions para crear una aplicación sin servidor con mensajería en tiempo real y el patrón de publicación y suscripción.

En este tutorial, aprenderá a:

  • Compilar una aplicación de chat en tiempo real sin servidor
  • Trabajar con enlaces de desencadenador de función y enlaces de salida de Web PubSub
  • Implementar la función en Azure Function App
  • Configurar la autenticación de Azure
  • Configurar el controlador de eventos de Web PubSub para enrutar los eventos y mensajes a la aplicación

Requisitos previos

Si no tiene una suscripción a Azure, cree una cuenta gratuita de Azure antes de empezar.

Inicio de sesión en Azure

Inicie sesión en Azure Portal en https://portal.azure.com/ con su cuenta de Azure.

Creación de una instancia de servicio de Azure Web PubSub

La aplicación se conectará a una instancia de servicio de Web PubSub en Azure.

  1. Seleccione el botón Nuevo de la esquina superior izquierda en Azure Portal. En la pantalla "Nuevo", escriba Web PubSub en el cuadro de búsqueda y presione Entrar. (También puede buscar Azure Web PubSub en la categoría Web).

    Captura de pantalla de la búsqueda de Azure Web PubSub en el portal.

  2. Seleccione Web PubSub en los resultados de la búsqueda y, después, haga clic en Crear.

  3. Escriba la siguiente configuración.

    Configuración Valor sugerido Descripción
    Nombre del recurso Nombre único globalmente Nombre único global que identifica la nueva instancia del servicio Web PubSub. Los caracteres válidos son a-z, A-Z, 0-9 y -.
    Suscripción Su suscripción Suscripción de Azure en la que se va a crear esta instancia del servicio Web PubSub.
    Grupo de recursos myResourceGroup Nombre del grupo de recursos nuevo en el que se va a crear la instancia del servicio Web PubSub.
    Ubicación Oeste de EE. UU. Seleccione una región cerca de usted.
    Plan de tarifa Gratuito Pruebe el servicio Azure Web PubSub de forma gratuita. Más información sobre los planes de tarifa del servicio Azure Web PubSub.
    Recuento de unidades - El recuento de unidades especifica cuántas conexiones puede aceptar la instancia del servicio Web PubSub. Cada unidad admite 1000 conexiones simultáneas como máximo. Solo es configurable en el nivel Estándar.

    Captura de pantalla de la creación de la instancia de Azure Web PubSub en el portal.

  4. Seleccione Crear para empezar a implementar la instancia del servicio Web PubSub.

Creación de las funciones

  1. Asegúrese de que Azure Functions Core Tools está instalado. Luego, cree un directorio vacío para el proyecto. Ejecute el comando en este directorio de trabajo.

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

    Confirme y actualice extensionBundle de host.json a la versión 4.* o posterior para obtener soporte para Web PubSub.

    {
      "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.*, 5.0.0)"
      }
    }
    
  3. Cree una función index para leer y hospedar una página web estática para los clientes.

    func new -n index -t HttpTrigger
    
    • Actualice src/functions/index.js y copie los siguientes códigos.
      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. Cree una función negotiate para ayudar a los clientes a obtener la dirección URL de conexión del servicio con el token de acceso.

    func new -n negotiate -t HttpTrigger
    

    Nota:

    En este ejemplo, usamos el encabezado de identidad de usuario de Microsoft Entra ID x-ms-client-principal-name para recuperar userId. No servirá en una función local. Puede dejarlo vacío o cambiar a otras formas de obtener o generar userId al reproducir en local. Por ejemplo, deje que el cliente escriba un nombre de usuario y lo pase en una consulta, como ?user={$username}, cuando llame a la función negotiate para obtener la dirección URL de conexión del servicio. Y en la función negotiate, establezca userId con el valor {query.user}.

    • Actualice src/functions/negotiate y copie los siguientes códigos.
      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. Cree una función message para difundir mensajes de clientes a través del servicio.

    func new -n message -t HttpTrigger
    
    • Actualice src/functions/message.js y copie los siguientes códigos.
      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. Agregue la página única del cliente index.html en la carpeta raíz del proyecto y copie el contenido.

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

Creación e implementación de una aplicación de funciones de Azure

Antes de poder implementar el código de la función en Azure, debe crear tres recursos:

  • Un grupo de recursos, que es un contenedor lógico de recursos relacionados.
  • Una cuenta de almacenamiento, que se usa para mantener el estado y otra información sobre sus funciones.
  • Una aplicación de funciones, que proporciona el entorno para ejecutar el código de función. Una aplicación de funciones se asigna a un proyecto de función local y le permite agrupar funciones como una unidad lógica, lo que facilita la administración, la implementación y el uso compartido de recursos.

Utilice los comandos siguientes para crear los elementos.

  1. Si todavía no lo ha hecho, inicie sesión en Azure:

    az login
    
  2. Cree un grupo de recursos. O bien, utilice el grupo de recursos del servicio Azure Web PubSub para omitir esta acción:

    az group create -n WebPubSubFunction -l <REGION>
    
  3. Cree una cuenta de almacenamiento de uso general en el grupo de recursos y la región:

    az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
    
  4. Cree la aplicación de funciones en 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

    Consulte la documentación de versiones en tiempo de ejecución de Azure Functions para establecer el parámetro --runtime-version al valor compatible.

  5. Implemente el proyecto de función en Azure:

    Después de haber creado correctamente su aplicación de funciones en Azure, está listo para implementar el proyecto de funciones local mediante el comando func azure functionapp publish.

    func azure functionapp publish <FUNCIONAPP_NAME>
    
  6. Configure el elemento WebPubSubConnectionString para la aplicación de funciones:

    En primer lugar, busque el recurso Web PubSub en Azure Portal y copie la cadena de conexión en Claves. A continuación, vaya a la configuración de la aplicación de funciones en Azure Portal ->Configuración ->Configuración. Y agregue un nuevo elemento en Configuración de la aplicación, con un nombre igual a WebPubSubConnectionString y el valor es la cadena de conexión del recurso Web PubSub.

Configuración Event Handler del servicio Web PubSub

En este ejemplo, se usa WebPubSubTrigger para escuchar las solicitudes ascendentes del servicio. Por lo tanto, Web PubSub tiene que conocer la información del punto de conexión de la función para enviar solicitudes de cliente de destino. Y la aplicación de funciones de Azure requiere una clave del sistema para la seguridad con respecto a los métodos de webhook específicos de la extensión. En el paso anterior, después de implementar la aplicación de funciones con funciones message, pudimos obtener la clave del sistema.

Vaya a Azure Portal -> Busque su recurso de aplicación de funciones ->Claves de la aplicación ->Claves del sistema ->webpubsub_extension. Copie el valor como <APP_KEY>.

Captura de pantalla de Obtener las claves del sistema de la función.

Establezca Event Handler en el servicio Azure Web PubSub. Vaya a Azure Portal -> Busque su recurso de Web PubSub ->Configuración. Agregue una nueva asignación de configuración del centro a la única función en uso. Reemplace <FUNCTIONAPP_NAME> y <APP_KEY> por los suyos.

  • Nombre del centro: simplechat
  • Plantilla de dirección URL:https://<NOMBRE_APLICACIÓNFUNCIONES>.azurewebsites.net/runtime/webhooks/webpubsub?code=<CLAVE_APLICACIÓN>
  • Patrón de evento de usuario: *
  • Eventos del sistema: (no es necesario configurar en este ejemplo)

Captura de pantalla de la configuración del controlador de eventos.

Configuración para habilitar la autenticación de cliente

Vaya a Azure Portal -> Busque su recurso de aplicación de funciones ->Autenticación. Haga clic en Add identity provider. Establezca la configuración de autenticación de App Service en Permitir acceso no autenticado para que los usuarios anónimos puedan visitar la página de índice del cliente antes de su redireccionamiento al proceso de autenticación. A continuación, guarde la operación.

Aquí elegimos Microsoft como proveedor de identificación, que utiliza x-ms-client-principal-name como userId en la función negotiate. Además, puede configurar otros proveedores de identidades siguiendo los vínculos. No olvide actualizar el valor userId de la función negotiate en consecuencia.

Prueba de la aplicación

Ahora puede probar la página desde la aplicación de funciones: https://<FUNCTIONAPP_NAME>.azurewebsites.net/api/index. Consulte la instantánea.

  1. Haga clic en login para autenticarse.
  2. Escriba el mensaje en el cuadro de entrada para chatear.

En la función message, se difunde el mensaje del autor de la llamada a todos los clientes y se devuelve el mensaje [SYSTEM] ack al autor de la llamada. Por tanto, en la instantánea de chat del ejemplo, sabemos que los cuatro primeros mensajes son del cliente actual y los dos últimos son de otro cliente.

Captura de pantalla del ejemplo de chat.

Limpieza de recursos

Si no va a seguir usando esta aplicación, siga los pasos que se indican a continuación para eliminar todos los recursos creados por este documento, con el fin de que no se le apliquen cargos:

  1. En Azure Portal, seleccione Grupos de recursos en el extremo izquierdo y luego seleccione el grupo de recursos que creó. Puede usar el cuadro de búsqueda para buscar el grupo de recursos por su nombre en su lugar.

  2. En la ventana que se abrirá, seleccione el grupo de recursos y luego seleccione Eliminar grupo de recursos.

  3. En la nueva ventana, escriba el nombre del grupo de recursos que desea eliminar y, después, seleccione Eliminar.

Pasos siguientes

En este inicio rápido, ha aprendido a ejecutar una aplicación de chat sin servidor. Ahora, puede empezar a crear su propia aplicación.