Поделиться через


Руководство. Создание бессерверного приложения для ведения чата в реальном времени с помощью Функций Azure и службы Azure Web PubSub

Служба Azure Web PubSub помогает создавать веб-приложения для обмена сообщениями в реальном времени с помощью подключений по протоколу WebSocket и шаблона "публикация — подписка". Функции Azure — бессерверная платформа, которая позволяет выполнять код без необходимости управлять какой-либо инфраструктурой. В этом учебнике описано, как использовать службу Azure Web PubSub и Функции Azure для создания бессерверного приложения с возможностью обмена сообщениями в реальном времени и шаблоном "публикация — подписка".

В этом руководстве описано следующее:

  • создать бессерверное приложение для ведения чата в реальном времени;
  • Работа с привязками триггера функции Web PubSub и привязками для вывода
  • развернуть функцию в приложении-функции Azure;
  • настроить аутентификацию Azure;
  • Настройка обработчика событий Web PubSub для маршрутизации событий и сообщений в приложение.

Внимание

Необработанные строки подключения приводятся в этой статье исключительно для демонстрации.

Строка подключения содержит сведения об авторизации, требуемые для доступа приложения к службе Azure Web PubSub. Ключ доступа в строке подключения аналогичен паролю привилегированного пользователя для службы. В рабочих средах всегда защищать ключи доступа. Используйте Azure Key Vault для безопасного управления ключами и защиты подключения.WebPubSubServiceClient

Старайтесь не распространять ключи доступа среди других пользователей, жестко программировать их или где-то сохранять в виде обычного текста в открытом доступе для других пользователей. Смените свои ключи, если предполагаете, что они могли быть скомпрометированы.

Необходимые компоненты

Если у вас еще нет подписки Azure, создайте бесплатную учетную запись Azure, прежде чем начинать работу.

Вход в Azure

Войдите на портал Azure по адресу https://portal.azure.com/ с помощью учетной записи Azure.

Создание экземпляра службы Azure Web PubSub

Приложение будет подключено к экземпляру службы Azure Web PubSub в Azure.

  1. Нажмите кнопку "Создать" в верхнем левом углу портала Azure. На экране "Создание" введите в поле поиска Web PubSub и нажмите клавишу ВВОД. (Можно также выполнить поиск по Azure Web PubSub в категории Web.)

    Снимок экрана: поиск по Azure Web PubSub на портале

  2. В результатах поиска выберите Web PubSub и щелкните Создать.

  3. Введите следующие параметры.

    Настройка Предлагаемое значение Описание
    Имя ресурса Глобально уникальное имя Глобально уникальное имя, которое идентифицирует ваш новый экземпляр службы Web PubSub. Допустимые символы: a-z, A-Z0-9и -.
    Подписка Ваша подписка Подписка Azure, в рамках которой создается новый экземпляр службы Web PubSub.
    Группа ресурсов мояГруппаРесурсов Имя новой группы ресурсов, в которой нужно создать экземпляр службы Web PubSub.
    Местонахождение западная часть США Выберите ближайший географический регион.
    Ценовая категория Бесплатно Вы можете сначала бесплатно поработать со службой Azure Web PubSub. Ознакомьтесь с ценовыми категориями службы Azure Web PubSub.
    Число единиц - Число единиц определяет количество подключений, которые поддерживает ваш экземпляр службы Web PubSub. Каждая единица поддерживает не более 1000 одновременных подключений. Это можно настроить только в стандартном уровне.

    Снимок экрана, где показан процесс создания экземпляра Azure Web PubSub на портале.

  4. Щелкните Создать, чтобы начать развертывание экземпляра службы Web PubSub.

Создание функций

  1. Убедитесь, что на компьютере установлен набор средств Azure Functions Core Tools. Затем создайте пустой каталог для проекта. Выполните команду в этом рабочем каталоге.

    func init --worker-runtime javascript --model V4
    
  2. Установите Microsoft.Azure.WebJobs.Extensions.WebPubSub.

    Подтвердите и обновите пакет расширений host.json до версии 4.* или более поздней, чтобы получить поддержку Web PubSub.

    {
      "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.*, 5.0.0)"
      }
    }
    
  3. Создайте функцию 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, 
              };
          }
      });
      
  4. Создайте функцию negotiate, чтобы клиенты могли получать URL-адрес подключения службы, используя токен доступа.

    func new -n negotiate -t HttpTrigger
    

    Примечание.

    В этом примере мы используем заголовок идентификатора пользователя Microsoft Entra IDx-ms-client-principal-name для извлечения userId. Это не сработает в локальной функции. Вы можете сделать его пустым или изменить на другие способы получения или создания 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')) };
          },
      });
      
  5. Создайте функцию 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",
              };
          }
      });
      
  6. Добавьте одну страницу 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, необходимо создать три ресурса:

  • группу ресурсов — логический контейнер связанных ресурсов;
  • учетная запись для хранения данных, которая используется для сохранения состояния и других сведений о ваших функциях.
  • Приложение-функция, которое предоставляет окружение для выполнения кода вашей функции. Приложение функций соответствует вашему локальному проекту функций и позволяет группировать функции в логические единицы для более простого управления, развертывания и совместного использования ресурсов.

Чтобы создать эти элементы, выполните следующие команды:

  1. Войдите в Azure, если вы еще этого не сделали:

    az login
    
  2. Создайте группу ресурсов или пропустите этот шаг, переиспользовав одну из существующих групп ресурсов службы Azure Web PubSub.

    az group create -n WebPubSubFunction -l <REGION>
    
  3. В группе ресурсов и регионе создайте учетную запись хранения общего назначения:

    az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
    
  4. Создайте приложение-функцию в 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 Functions, чтобы установить параметр --runtime-version на поддерживаемое значение.

  5. Разверните проект функций в Azure:

    После успешного создания приложения-функции в Azure вы готовы развернуть свой проект локальных функций, используя команду func azure functionapp publish.

    func azure functionapp publish <FUNCIONAPP_NAME>
    
  6. Настройте WebPubSubConnectionString для функционального приложения.

    Сырые строки подключения появляются в этой статье только в демонстрационных целях. В рабочих средах всегда защищать ключи доступа. Используйте Azure Key Vault для безопасного управления и ротации ключей, а также защиты вашего подключения с помощью WebPubSubServiceClient.

    Сначала найдите ресурс Web PubSub на портале Azure и скопируйте строку подключения в разделе Ключи. Затем перейдите к настройкам функции приложения в портале Azure ->Настройки ->переменные среды. И добавьте новый элемент в параметры приложения, с именем 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 —>настройки. Добавьте новое сопоставление настроек хаба к используемой функции. Замените <FUNCTIONAPP_NAME> и <APP_KEY> на ваши значения.

  • Имя концентратора: simplechat
  • Шаблон URL-адреса: https://<FUNCTIONAPP_NAME>.azurewebsites.net/runtime/webhooks/webpubsub?<code=>APP_KEY
  • Шаблон пользовательского события: *.
  • Системные события: (в этом примере не настраивается)

Снимок экрана: задание обработчика событий.

Настройка для включения аутентификации клиента

Перейдите к порталу Azure—> найдите ваш ресурс функции приложения —>Аутентификация. Нажмите кнопку Add identity provider. Установите параметры аутентификации для Службы приложений на Разрешить неаутентифицированный доступ, чтобы анонимные пользователи могли посетить основную страницу клиента перед перенаправлением на аутентификацию. Затем нажмите кнопку Сохранить.

Здесь мы выбираем Microsoft поставщика, который использует x-ms-client-principal-name в качестве userId в функции negotiate. Кроме того, вы можете настроить других поставщиков удостоверений, следуя по этим ссылкам, и не забудьте обновить значение функции negotiate соответствующим образом.

Проверка работы приложения

Теперь вы можете протестировать страницу из функционального приложения: https://<FUNCTIONAPP_NAME>.azurewebsites.net/api/index. См. скриншот.

  1. Щелкните login, чтобы пройти аутентификацию.
  2. Введите текст сообщения в поле ввода, чтобы начать чат.

В функции сообщения мы транслируем сообщение отправителя всем клиентам и возвращаем отправителя с сообщением [SYSTEM] ack. Поэтому мы можем знать в примере моментального снимка чата, первые четыре сообщения из текущего клиента, а последние два сообщения — от другого клиента.

Снимок экрана: пример чата.

Очистка ресурсов

Если вы не собираетесь использовать это приложение дальше, удалите все ресурсы, созданные этим документом, чтобы избежать расходов.

  1. На портале Azure выберите Группа ресурсов слева, а затем созданную группу ресурсов. Вместо этого вы можете использовать поле поиска для поиска ресурса по его имени.

  2. В открывшемся окне выберите группу ресурсов и щелкните Удалить группу ресурсов.

  3. В новом окне введите имя удаляемой группы ресурсов и щелкните Удалить.

Следующие шаги

В этом кратком руководстве вы узнали, как запустить бессерверное приложение чата. Теперь можно приступить к созданию собственного приложения.