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 o WebSockets e o padrão de publicação-assinatura com facilidade. O Azure Functions é uma plataforma sem servidor que permite executar seu código sem gerenciar qualquer infraestrutura. Neste tutorial, você aprende como 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 de publicação-assinatura.
Neste tutorial, você aprenderá como:
- Criar um aplicativo de chat em tempo real sem servidor
- Trabalhar com as associações de gatilho de função e as associações de saída do Web PubSub
- Implantar a função no aplicativo de funções do Azure
- Configurar a autenticação do Azure
- Configurar o manipulador de eventos do Web PubSub para rotear eventos e mensagens para o aplicativo
Pré-requisitos
Um editor de códigos, como o Visual Studio Code
Node.js versão 18.x ou posterior.
Observação
Para obter mais informações sobre as versões compatíveis do Node.js, confira a documentação das versões de runtime do Azure Functions.
Azure Functions Core Tools (v4 ou superior, preferencialmente) para executar aplicativos de função do Azure localmente e implantar no Azure.
A CLI do Azure para gerenciar recursos do Azure.
Caso você não tenha uma assinatura do Azure, crie uma conta gratuita do Azure antes de começar.
Entrar no Azure
Entre no portal do Azure em https://portal.azure.com/ com sua conta do Azure.
Criar uma instância do serviço Azure Web PubSub
Seu aplicativo se conectará a uma instância do serviço Web PubSub no Azure.
Selecione no botão Novo localizado 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 categoria
Web
.)Selecione Web PubSub nos resultados da pesquisa e escolha Criar.
Insira as configurações a seguir.
Configuração Valor sugerido Descrição Nome do recurso Nome globalmente exclusivo O Nome globalmente exclusivo que identifica a nova instância do serviço Azure Web PubSub. Os caracteres válidos são a-z
,A-Z
,0-9
e-
.Assinatura Sua assinatura A assinatura do Azure na qual essa nova instância do serviço Azure Web PubSub será criada. Grupo de Recursos myResourceGroup Nome do novo grupo de recursos no qual a instância do serviço Azure Web PubSub será criada. Localidade Oeste dos EUA Selecione uma região perto de você. Tipo de preços Grátis Primeiro, você pode experimentar o serviço Azure Web PubSub gratuitamente. Saiba mais detalhes sobre os tipos de preços do serviço Azure Web PubSub Contagem de unidades - A contagem de unidades especifica quantas conexões a instância do serviço Azure Web PubSub pode aceitar. Cada unidade dá suporte a, no máximo, 1.000 conexões simultâneas. Só é configurável na camada Standard. Selecione Criar para começar a implantar a instância do serviço Azure Web PubSub.
Criar as funções
Verifique se você tem o Azure Functions Core Tools instalado. E, em seguida, criar um diretório vazio para o projeto. Execute o comando neste diretório de trabalho.
func init --worker-runtime javascript --model V4
Instale o
Microsoft.Azure.WebJobs.Extensions.WebPubSub
.Confirme e atualize o extensionBundle do
host.json
para a versão 4.* ou posterior, para obter suporte ao Web PubSub.{ "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[4.*, 5.0.0)" } }
Crie uma função
index
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, }; } });
- Atualize
Crie uma função
negotiate
para ajudar os clientes a obterem a URL de conexão do serviço com o token de acesso.func new -n negotiate -t HttpTrigger
Observação
Neste exemplo, usamos o cabeçalho de identidade do usuário do Microsoft Entra ID
x-ms-client-principal-name
para recuperaruserId
. Isso não funcionará em uma função local. Você pode torná-lo vazio ou usar outras formas de obter ou gerar auserId
na execução local. Por exemplo, permita que o cliente digite um nome de usuário e o transmita em uma consulta como?user={$username}
quando chamar a funçãonegotiate
para obter a URL de conexão do serviço. Na funçãonegotiate
, definauserId
com o 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')) }; }, });
- Atualize
Crie uma função
message
para transmitir mensagens do cliente por meio 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", }; } });
- Atualize
Adicione a página única do cliente
index.html
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 de Funções do Azure
Antes de poder implantar o código da 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ções, que fornece o ambiente para a execução do código de função. Um aplicativo de funções é mapeado 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.
Se você ainda não tiver feito isso, entre no Azure:
az login
Crie um grupo de recursos ou ignore essa etapa reutilizando o do serviço do Azure Web PubSub:
az group create -n WebPubSubFunction -l <REGION>
Crie uma conta de armazenamento para uso geral no grupo de recursos e na região:
az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
Criar o aplicativo de funções 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>
Observação
Verifique a documentação das versões de tempo de execução do Azure Functions para definir o parâmetro
--runtime-version
para o valor com suporte.Implantar o projeto de funções no Azure:
Depois de criar com sucesso o aplicativo de funções no Azure, você estará pronto para implantar o projeto de funções local usando o comando func azure functionapp publish.
func azure functionapp publish <FUNCIONAPP_NAME>
Configure o
WebPubSubConnectionString
para o aplicativo de funções:Primeiro, encontre seu recurso do Web PubSub no portal do Azure e copie a cadeia de conexão em Chaves. Depois, acesse as configurações do Aplicativo de Funções em Portal do Azure ->Configurações ->Configuração. Além disso, adicione um novo item em Configurações de aplicativo, com um nome igual a
WebPubSubConnectionString
e o valor como a cadeia de conexão do recurso do Web PubSub.
Configurar o serviço Web PubSub Event Handler
Neste exemplo, usamos WebPubSubTrigger
para escutar as solicitações upstream do serviço. Portanto, o Web PubSub precisa saber as informações do ponto de extremidade da função para enviar solicitações de cliente de destino. Além disso, o aplicativo de funções do Azure exige uma chave do sistema para segurança em relação aos métodos de webhook específicos da extensão. Na etapa anterior, depois de implantarmos o aplicativo de funções com as funções message
, obteremos a chave do sistema.
Acesse Portal do Azure -> localize seu recurso do Aplicativo de Funções ->Chaves do aplicativo ->Chaves do sistema ->webpubsub_extension
. Copie o valor como <APP_KEY>
.
Defina Event Handler
no serviço Azure Web PubSub. Acesse Portal do Azure -> localize seu recurso do Web PubSub ->Configurações. Adicione um novo mapeamento de configurações de hub para a função em uso. Substitua o <FUNCTIONAPP_NAME>
e a <APP_KEY>
pelas suas informações.
- 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 essa opção neste exemplo)
Configurar o para habilitar a autenticação de cliente
Acesse Portal do Azure -> localize seu recurso do Aplicativo de Funções ->Autenticação. Clique em Add identity provider
. Defina as configurações de autenticação do Serviço de Aplicativo como Permitir o acesso não autenticado, de modo que a página de índice do cliente possa ser visitada por usuários anônimos antes de redirecioná-los para autenticação. Em seguida, Salve.
Aqui, escolhemos Microsoft
como o provedor de identidade, que usa x-ms-client-principal-name
como userId
na função negotiate
. Além disso, você pode configurar outros provedores de identidade seguindo os links. Não se esqueça de atualizar o valor userId
na função negotiate
de acordo.
Experimentar o aplicativo
Agora você poderá testar sua página no aplicativo de funções: https://<FUNCTIONAPP_NAME>.azurewebsites.net/api/index
. Veja o instantâneo.
- Clique em
login
para se autenticar. - Digite uma mensagem na caixa de entrada para conversar.
Na função de mensagem, transmitimos a mensagem do chamador para todos os clientes e retornar o chamador com a mensagem [SYSTEM] ack
. Portanto, podemos saber no instantâneo de exemplo de chat que as primeiras quatro mensagens são do cliente atual e as duas últimas mensagens são de outro cliente.
Limpar recursos
Se você não pretende continuar usando este aplicativo, exclua todos os recursos criados por este documento com as seguintes etapas para não gerar custos:
No portal do Azure, selecione Grupos de recursos na extremidade esquerda, depois selecione o recurso de grupo que você criou. Você poderá usar a caixa de pesquisa para localizar o grupo de recursos pelo nome.
Na janela que será aberta, selecione o grupo de recursos e escolha Excluir grupo de recursos.
Na nova janela, digite o nome do grupo de recursos a ser excluído e selecione Excluir.
Próximas etapas
Neste início rápido, você aprendeu a executar um aplicativo de chat sem servidor. Agora, você pode começar a criar seu próprio aplicativo.