Руководство. Создание бессерверного приложения для ведения чата в реальном времени с помощью Функций Azure и службы Azure Web PubSub
Служба Azure Web PubSub помогает создавать веб-приложения для обмена сообщениями в реальном времени с помощью подключений по протоколу WebSocket и шаблона "публикация — подписка". Функции Azure — бессерверная платформа, которая позволяет выполнять код без необходимости управлять какой-либо инфраструктурой. В этом учебнике описано, как использовать службу Azure Web PubSub и Функции Azure для создания бессерверного приложения с возможностью обмена сообщениями в реальном времени и шаблоном "публикация — подписка".
В этом руководстве описано следующее:
- создать бессерверное приложение для ведения чата в реальном времени;
- работать с привязками триггера функции Web PubSub и выходными привязками;
- развернуть функцию в приложении-функции Azure;
- настроить аутентификацию Azure;
- Настройка обработчика событий Web PubSub для маршрутизации событий и сообщений в приложение.
Необходимые компоненты
Редактор кода, например Visual Studio Code.
Node.js версии 18.x или более поздней.
Примечание.
Дополнительные сведения о поддерживаемых версиях Node.js см. в документации по версиям среды выполнения Функций Azure.
Функции Azure Core Tools (4 или более поздней версии) для локального запуска приложений-функций Azure и развертывания в Azure.
Azure CLI для управления ресурсами Azure.
Если у вас еще нет подписки Azure, создайте бесплатную учетную запись Azure, прежде чем начинать работу.
Вход в Azure
Войдите на портал Azure по адресу https://portal.azure.com/ с помощью учетной записи Azure.
Создание экземпляра службы Azure Web PubSub
Приложение будет подключено к экземпляру службы Azure Web PubSub в Azure.
Нажмите кнопку "Создать" в верхнем левом углу портала Azure. На экране "Создание" введите в поле поиска Web PubSub и нажмите клавишу ВВОД. (Можно также выполнить поиск по Azure Web PubSub в категории
Web
.)В результатах поиска выберите Web PubSub и щелкните Создать.
Введите следующие параметры.
Параметр Предлагаемое значение Description Имя ресурса Глобально уникальное имя Глобально уникальное имя, которое определяет новый экземпляр службы Web PubSub. Допустимые символы: a-z
,0-9
A-Z
и-
.Подписка Ваша подписка Подписка Azure, в рамках которой создается экземпляр службы Web PubSub. Группа ресурсов myResourceGroup Имя новой группы ресурсов, в которой будет создан экземпляр службы Web PubSub. Местонахождение западная часть США Выберите ближайший географический регион. Ценовая категория Бесплатно Вы можете сначала бесплатно поработать со службой Azure Web PubSub. Ознакомьтесь с ценовыми категориями службы Azure Web PubSub. Число единиц - Число единиц определяет количество подключений, которые поддерживает ваш экземпляр службы Web PubSub. Каждая единица поддерживает не более 1000 одновременных подключений. Это можно настроить только для цен. категории "Стандартный". Щелкните Создать, чтобы начать развертывание экземпляра службы Web PubSub.
Создание функций
Убедитесь, что на компьютере установлен набор средств Azure Functions Core Tools. Затем создайте пустой каталог для проекта. Выполните команду в этом рабочем каталоге.
func init --worker-runtime javascript --model V4
Установите
Microsoft.Azure.WebJobs.Extensions.WebPubSub
.Подтвердите и обновите
host.json
расширениеBundle до версии 4.* или более поздней, чтобы получить поддержку Web PubSub.{ "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[4.*, 5.0.0)" } }
Создайте функцию
index
для чтения и размещения статической веб-страницы для клиентов.func new -n index -t HttpTrigger
- Обновите файл
src/functions/index.js
и скопируйте приведенные ниже фрагменты кода.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, }; } });
- Обновите файл
Создайте функцию
negotiate
, чтобы клиенты могли получать URL-адрес подключения службы с помощью маркера доступа.func new -n negotiate -t HttpTrigger
Примечание.
В этом примере для извлечения
userId
используется заголовокx-ms-client-principal-name
идентификатора пользователя Microsoft Entra ID. И это не будет работать в локальной функции. Вы можете сделать его пустым или изменить другим образом либо создатьuserId
при локальном использовании. Например, клиент может ввести имя пользователя и передать его в запрос, как?user={$username}
при вызове функцииnegotiate
для получения URL-адреса подключения службы. В функцииnegotiate
задайте параметрuserId
со значением{query.user}
.- Обновите файл
src/functions/negotiate
и скопируйте приведенные ниже фрагменты кода.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')) }; }, });
- Обновите файл
Создайте функцию
message
для рассылки сообщений клиентам через службу.func new -n message -t HttpTrigger
- Обновите файл
src/functions/message.js
и скопируйте приведенные ниже фрагменты кода.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", }; } });
- Обновите файл
Добавьте одну страницу
index.html
клиента в корневую папку проекта и скопируйте содержимое.<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>
Создание и развертывание приложения-функции Azure
Прежде чем развернуть код функции в Azure, необходимо создать три ресурса:
- группу ресурсов — логический контейнер связанных ресурсов;
- учетную запись хранения, которая используется для сохранения состояния и других сведений о функциях;
- Приложение-функция, которое предоставляет окружение для выполнения кода вашей функции. Оно сопоставляется с локальным проектом функций и позволяет группировать функции в логические единицы, чтобы упростить развертывание, масштабирование и совместное использование ресурсов, а также управление ими.
Чтобы создать эти элементы, выполните следующие команды:
Войдите в Azure, если вы еще этого не сделали:
az login
Создайте группу ресурсов или можно пропустить, повторно выполнив одну из служб Azure Web PubSub:
az group create -n WebPubSubFunction -l <REGION>
В группе ресурсов и регионе создайте учетную запись хранения общего назначения:
az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
Создайте приложение-функцию в 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>
Примечание.
Проверьте Функции Azure документацию по версиям среды выполнения, чтобы задать
--runtime-version
для параметра поддерживаемое значение.Разверните проект функций в Azure:
После успешного создания приложения-функции в Azure теперь можно развернуть проект локальных функций с помощью команды публикации func azure functionapp.
func azure functionapp publish <FUNCIONAPP_NAME>
Настройте
WebPubSubConnectionString
для приложения-функции:Сначала найдите ресурс Web PubSub на портале Azure и скопируйте строку подключения в разделе Ключи. Затем перейдите к параметрам приложения-функции на портале Azure ->Settings ->Configuration. И добавьте новый элемент в разделе Параметры приложения с именем
WebPubSubConnectionString
, указав в качестве значения свою строку подключения к ресурсу Web PubSub.
Настройка Event Handler
службы Web PubSub
В этом примере с помощью WebPubSubTrigger
мы будем прослушивать вышестоящие запросы службы. Поэтому службе Web PubSub требуются сведения о конечной точке функции для отправки запросов целевых клиентов. А приложению-функции Azure требуется системный ключ для обеспечения безопасности в отношении методов веб-перехватчиков, зависящих от расширения. После развертывания приложения-функции с помощью функций message
на предыдущем шаге мы можем получить системный ключ.
Перейдите к портал Azure. Поиск ресурса приложения-функции ->Ключи приложения ->Системные ключи ..webpubsub_extension
>> Скопируйте значение как <APP_KEY>
.
Задайте Event Handler
в службе Azure Web PubSub. Перейдите к портал Azure —> найдите ресурс Web PubSub ->Settings. Добавьте новое сопоставление параметров концентратора в используемую функцию. Замените <FUNCTIONAPP_NAME>
и <APP_KEY>
соответствующими значениями.
- Имя концентратора:
simplechat
- Шаблон URL-адреса: https://< FUNCTIONAPP_NAME.azurewebsites.net/runtime/webhooks/webpubsub?code>=<APP_KEY>
- Шаблон пользовательского события: *.
- Системные события: (в этом примере не настраивается)
Настройка для включения аутентификации клиента
Перейдите к портал Azure—> поиск ресурса приложения-функции —>Authentication. Нажмите кнопку Add identity provider
. Задайте для параметра проверки подлинности Служба приложений значение Allow unauthenticated access, чтобы страница индекса клиента можно просматривать анонимными пользователями перед перенаправлением для проверки подлинности. Затем нажмите кнопку Сохранить.
Здесь мы выбираем Microsoft
поставщик, который используется x-ms-client-principal-name
как userId
в negotiate
функции. Кроме того, вы можете настроить других поставщиков удостоверений, следуя ссылкам, и не забудьте обновить userId
значение в negotiate
функции соответствующим образом.
Проверка работы приложения
Теперь вы можете протестировать страницу из приложения-функции: https://<FUNCTIONAPP_NAME>.azurewebsites.net/api/index
. См. моментальный снимок.
- Щелкните
login
, чтобы пройти аутентификацию. - Введите текст сообщения в поле ввода, чтобы начать чат.
В функции сообщения мы транслируем сообщение вызывающего абонента всем клиентам и возвращаем вызывающий объект с сообщением [SYSTEM] ack
. Поэтому мы можем знать в примере моментального снимка чата, первые четыре сообщения из текущего клиента, а последние два сообщения — от другого клиента.
Очистка ресурсов
Если вы не собираетесь использовать это приложение дальше, удалите все ресурсы, созданные в ходе работы с этим кратким руководством, чтобы не оплачивать их.
На портале Azure выберите Группа ресурсов слева, а затем созданную группу ресурсов. Вместо этого вы можете использовать поле поиска для поиска ресурса по его имени.
В открывшемся окне выберите группу ресурсов и щелкните Удалить группу ресурсов.
В новом окне введите имя удаляемой группы ресурсов и щелкните Удалить.
Следующие шаги
В этом кратком руководстве вы узнали, как запустить бессерверное приложение чата. Теперь можно приступить к созданию собственного приложения.