Share via


Tutorial: Criar um aplicativo de chat em tempo real sem servidor com o Azure Functions e o serviço Azure Web PubSub

O serviço Azure Web PubSub ajuda você a criar aplicativos Web de mensagens em tempo real usando WebSockets e o padrão publish-subscribe facilmente. As Funções do Azure são uma plataforma sem servidor que lhe permite executar código sem ter de gerir qualquer infraestrutura. Neste tutorial, você aprenderá a usar o serviço Azure Web PubSub e o Azure Functions para criar um aplicativo sem servidor com mensagens em tempo real e o padrão publicar-assinar.

Neste tutorial, irá aprender a:

  • Crie um aplicativo de bate-papo em tempo real sem servidor
  • Trabalhar com ligações de gatilho da função Web PubSub e ligações de saída
  • Implantar a função no Azure Function App
  • Configurar a Autenticação do Azure
  • Configurar o manipulador de eventos Web PubSub para rotear eventos e mensagens para o aplicativo

Pré-requisitos

  • Um editor de código, como o Visual Studio Code

  • Node.js, versão 18.x ou superior.

    Nota

    Para obter mais informações sobre as versões com suporte do Node.js, consulte a documentação de versões de tempo de execução do Azure Functions.

  • Ferramentas Principais do Azure Functions (v4 ou superior preferencial) para executar aplicativos do Azure Function localmente e implantar no Azure.

  • A CLI do Azure para gerenciar recursos do Azure.

Se não tiver uma subscrição do Azure, crie uma conta gratuita do Azure antes de começar.

Iniciar sessão no Azure

Inicie sessão no portal do Azure em https://portal.azure.com/ com a sua conta do Azure.

Criar uma instância de serviço Azure Web PubSub

Seu aplicativo se conectará a uma instância de serviço Web PubSub no Azure.

  1. Selecione o botão Novo, no canto superior esquerdo do portal do Azure. Na tela Novo, digite Web PubSub na caixa de pesquisa e pressione enter. (Você também pode pesquisar o Azure Web PubSub na Web categoria.)

    Captura de ecrã a mostrar a pesquisa do Azure Web PubSub no portal.

  2. Selecione Web PubSub nos resultados da pesquisa e, em seguida, selecione Criar.

  3. Introduza as seguintes definições.

    Definição Valor sugerido Description
    Nome do recurso Nome globalmente exclusivo O Nome globalmente exclusivo que identifica sua nova instância de serviço Web PubSub. Os caracteres válidos são a-z, A-Z, 0-9, e -.
    Subscrição a sua subscrição A assinatura do Azure sob a qual essa nova instância de serviço Web PubSub é criada.
    Grupo de Recursos myResourceGroup Nome para o novo grupo de recursos no qual criar sua instância de serviço Web PubSub.
    Location E.U.A. Oeste Escolha uma região perto de si.
    Escalão de preço Gratuito Primeiro, você pode experimentar o serviço Azure Web PubSub gratuitamente. Saiba mais detalhes sobre os níveis de preços do serviço Azure Web PubSub
    Contagem de unidades - A contagem de unidades especifica quantas conexões sua instância de serviço Web PubSub pode aceitar. Cada unidade suporta no máximo 1.000 conexões simultâneas. Pode configurar apenas no escalão Standard.

    Captura de ecrã da criação da instância do Azure Web PubSub no portal.

  4. Selecione Criar para iniciar a implantação da instância do serviço Web PubSub.

Criar as funções

  1. Certifique-se de que tem as Ferramentas Principais do Azure Functions instaladas. E, em seguida, crie um diretório vazio para o projeto. Execute o comando neste diretório de trabalho.

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

    Confirme e atualize host.jsono extensionBundle para a versão 4.* ou posterior para obter suporte ao Web PubSub.

    {
      "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.*, 5.0.0)"
      }
    }
    
  3. Crie uma index função para ler e hospedar uma página da Web estática para clientes.

    func new -n index -t HttpTrigger
    
    • Atualize src/functions/index.js e copie os seguintes 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. Crie uma função para ajudar os clientes a obter URL de negotiate conexão de serviço com token de acesso.

    func new -n negotiate -t HttpTrigger
    

    Nota

    Neste exemplo, usamos o cabeçalho x-ms-client-principal-name de identidade do usuário do Microsoft Entra ID para recuperar userIdo . E isso não funcionará em uma função local. Você pode deixá-lo vazio ou mudar para outras maneiras de obter ou gerar userId ao jogar no local. Por exemplo, permita que o cliente digite um nome de usuário e passe-o em consulta como ?user={$username} quando chamar negotiate a função para obter a URL da conexão de serviço. E na negotiate função, definir userId com valor {query.user}.

    • Atualize src/functions/negotiate e copie os seguintes 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. Crie uma message função para transmitir mensagens do cliente através do serviço.

    func new -n message -t HttpTrigger
    
    • Atualize src/functions/message.js e copie os seguintes 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. Adicione a página index.html única do cliente na pasta raiz do projeto e copie o conteúdo.

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

Criar e implantar o aplicativo Azure Function

Antes de implantar seu código de função no Azure, você precisa criar três recursos:

  • Um grupo de recursos, que é um contêiner lógico para recursos relacionados.
  • Uma conta de armazenamento, que é usada para manter o estado e outras informações sobre suas funções.
  • Um aplicativo de função, que fornece o ambiente para executar seu código de função. Um aplicativo de função mapeia para seu projeto de função local e permite agrupar funções como uma unidade lógica para facilitar o gerenciamento, a implantação e o compartilhamento de recursos.

Use os comandos a seguir para criar esses itens.

  1. Se ainda não o fez, inicie sessão no Azure:

    az login
    
  2. Crie um grupo de recursos ou você pode ignorar reutilizando o do serviço Azure Web PubSub:

    az group create -n WebPubSubFunction -l <REGION>
    
  3. Crie uma conta de armazenamento de uso geral em seu grupo de recursos e região:

    az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
    
  4. Crie o aplicativo de função no 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

    Verifique a documentação das versões de tempo de execução do Azure Functions para definir --runtime-version o parâmetro como valor suportado.

  5. Implante o projeto de função no Azure:

    Depois de criar com êxito seu aplicativo de função no Azure, você está pronto para implantar seu projeto de funções locais usando o comando func azure functionapp publishing .

    func azure functionapp publish <FUNCIONAPP_NAME>
    
  6. Configure o WebPubSubConnectionString para o aplicativo de função:

    Primeiro, localize seu recurso Web PubSub do Portal do Azure e copie a cadeia de conexão em Chaves. Em seguida, navegue até Configurações do aplicativo de função no Portal do Azure ->Settings ->Configuration. E adicione um novo item em Configurações do aplicativo, com nome igual e valor é sua cadeia de WebPubSubConnectionString conexão de recurso Web PubSub.

Configurar o serviço Web PubSub Event Handler

Neste exemplo, estamos usando WebPubSubTrigger para ouvir solicitações de serviço upstream. Portanto, o Web PubSub precisa conhecer as informações de ponto final da função para enviar solicitações de clientes alvo. E o Azure Function App requer uma chave do sistema para segurança em relação a métodos de webhook específicos de extensão. Na etapa anterior, depois de implantarmos o aplicativo de função com message funções, conseguimos obter a chave do sistema.

Vá para o portal do Azure -> Encontre seu recurso do aplicativo de função ->Chaves do aplicativo ->Chaves do sistema ->webpubsub_extension. Copie o valor como <APP_KEY>.

Screenshot de obter teclas do sistema de função.

Definido Event Handler no serviço Azure Web PubSub. Vá para o portal do Azure -> Encontre seu recurso Web PubSub ->Settings. Adicione um novo mapeamento de configurações de hub para a função em uso. Substitua o e <APP_KEY> para o <FUNCTIONAPP_NAME> seu.

  • Nome do Hub: simplechat
  • Modelo de URL: https://< FUNCTIONAPP_NAME.azurewebsites.net/runtime/webhooks/webpubsub?code>=<APP_KEY>
  • Padrão de evento do usuário: *
  • Eventos do sistema: -(Não é necessário configurar neste exemplo)

Captura de tela da configuração do manipulador de eventos.

Configurar para habilitar a autenticação do cliente

Vá para o portal do Azure -> Encontre seu recurso de aplicativo de função ->Autenticação. Clique em Add identity provider. Defina as configurações de autenticação do Serviço de Aplicativo como Permitir acesso não autenticado, para que sua página de índice do cliente possa ser visitada por usuários anônimos antes de redirecionar para autenticação. Em seguida, salve.

Aqui escolhemos Microsoft como provedor de identificação, que usa x-ms-client-principal-name como userId na negotiate função. Além disso, você pode configurar outros provedores de identidade seguindo os links, e não se esqueça de atualizar o userId valor na função de negotiate acordo.

Experimentar a aplicação

Agora você pode testar sua página a partir do seu aplicativo de função: https://<FUNCTIONAPP_NAME>.azurewebsites.net/api/index. Veja o instantâneo.

  1. Clique login para se autenticar.
  2. Digite mensagem na caixa de entrada para conversar.

Na função de mensagem, transmitimos a mensagem do chamador para todos os clientes e retornamos o chamador com a mensagem [SYSTEM] ack. Assim, podemos saber no exemplo de instantâneo de bate-papo, as primeiras quatro mensagens são do cliente atual e as duas últimas mensagens são de outro cliente.

Captura de tela do exemplo de bate-papo.

Clean up resources (Limpar recursos)

Se você não vai continuar a usar este aplicativo, exclua todos os recursos criados por este documento com as seguintes etapas para não incorrer em nenhum custo:

  1. No portal do Azure, selecione Grupos de recursos à esquerda e, em seguida, selecione o grupo de recursos que criou. Em vez disso, você pode usar a caixa de pesquisa para localizar o grupo de recursos pelo nome.

  2. Na janela que se abre, selecione o grupo de recursos e, em seguida, selecione Eliminar grupo de recursos.

  3. Na nova janela, digite o nome do grupo de recursos a ser excluído e selecione Excluir.

Próximos passos

Neste início rápido, você aprendeu como executar um aplicativo de chat sem servidor. Agora, você pode começar a criar seu próprio aplicativo.