Sdílet prostřednictvím


Kurz: Sestavení chatovací aplikace pomocí funkce Azure Functions v bezserverovém režimu (Preview)

V tomto kurzu se dozvíte, jak vytvořit web pubSub pro Socket.IO službu v bezserverovém režimu a vytvořit chatovací aplikaci integrující se službou Azure Functions.

Vyhledejte úplné ukázky kódu, které se používají v tomto kurzu:

Důležité

Výchozí režim vyžaduje trvalý server. Web PubSub nelze integrovat pro Socket.IO ve výchozím režimu s funkcí Azure Functions.

Důležité

Surové připojovací řetězce jsou v tomto článku uvedeny jen pro demonstrační účely.

Připojovací řetězec obsahuje informace o autorizaci potřebné pro to, aby vaše aplikace měla přístup ke službě Azure Web PubSub. Přístupový klíč uvnitř připojovacího řetězce je podobný kořenovému heslu pro vaši službu. V produkčních prostředích vždy chraňte přístupové klíče. Použijte Azure Key Vault k bezpečné správě a rotaci klíčů a zabezpečte své připojení pomocí WebPubSubServiceClient.

Vyhněte se distribuci přístupových klíčů ostatním uživatelům, jejich pevnému kódování nebo jejich uložení kdekoli ve formátu prostého textu, který je přístupný ostatním uživatelům. Otočte klíče, pokud se domníváte, že mohly být ohroženy.

Požadavky

Vytvoření webového pubSub pro prostředek Socket.IO v bezserverovém režimu

K vytvoření Web PubSub pro Socket.IO můžete použít následující příkaz Azure CLI:

az webpubsub create -g <resource-group> -n <resource-name>--kind socketio --service-mode serverless --sku Premium_P1

Vytvoření projektu Azure Functions místně

Měli byste postupovat podle kroků a inicializovat místní projekt funkce Azure Functions.

  1. Podle pokynů nainstalujte nejnovější nástroj azure Functions Core

  2. V okně terminálu nebo z příkazového řádku spusťte následující příkaz, který vytvoří projekt ve SocketIOProject složce:

    func init SocketIOProject --worker-runtime javascript --model V4
    

    Tento příkaz vytvoří projekt JavaScriptu. A zadáním složky SocketIOProject spusťte následující příkazy.

  3. V současné době Balíček funkcí neobsahuje vazbu funkce Socket.IO, takže tento balíček musíte přidat ručně.

    1. Pokud chcete odstranit odkaz na sadu funkcí, upravte soubor host.json a odeberte následující řádky.

      "extensionBundle": {
          "id": "Microsoft.Azure.Functions.ExtensionBundle",
          "version": "[4.*, 5.0.0)"
      }
      
    2. Spusťte příkaz:

      func extensions install -p Microsoft.Azure.WebJobs.Extensions.WebPubSubForSocketIO -v 1.0.0-beta.4
      
  4. Vytvořte funkci pro vyjednávání. Funkce vyjednávání používaná ke generování koncových bodů a tokenů pro klientský přístup ke službě.

    func new --template "Http Trigger" --name negotiate
    

    Otevřete soubor v src/functions/negotiate.js a nahraďte jej následujícím kódem:

    const { app, input } = require('@azure/functions');
    
    const socketIONegotiate = input.generic({
        type: 'socketionegotiation',
        direction: 'in',
        name: 'result',
        hub: 'hub'
    });
    
    async function negotiate(request, context) {
        let result = context.extraInputs.get(socketIONegotiate);
        return { jsonBody: result };
    };
    
    // Negotiation
    app.http('negotiate', {
        methods: ['GET', 'POST'],
        authLevel: 'anonymous',
        extraInputs: [socketIONegotiate],
        handler: negotiate
    });
    

    Tento krok vytvoří funkci negotiate s triggerem HTTP a SocketIONegotiation výstupní vazbou, což znamená, že k aktivaci funkce můžete použít volání HTTP a vrátit výsledek vyjednávání vygenerovaný SocketIONegotiation vazbou.

  5. Vytvořte funkci pro předávání zpráv.

    func new --template "Http Trigger" --name message
    

    Otevřete soubor src/functions/message.js a nahraďte ho následujícím kódem:

    const { app, output, trigger } = require('@azure/functions');
    
    const socketio = output.generic({
    type: 'socketio',
    hub: 'hub',
    })
    
    async function chat(request, context) {
        context.extraOutputs.set(socketio, {
        actionName: 'sendToNamespace',
        namespace: '/',
        eventName: 'new message',
        parameters: [
            context.triggerMetadata.socketId,
            context.triggerMetadata.message
        ],
        });
    }
    
    // Trigger for new message
    app.generic('chat', {
        trigger: trigger.generic({
            type: 'socketiotrigger',
            hub: 'hub',
            eventName: 'chat',
            parameterNames: ['message'],
        }),
        extraOutputs: [socketio],
        handler: chat
    });
    

    Tento příkaz SocketIOTrigger se používá k tomu, aby se spustil na základě zprávy klienta Socket.IO, a SocketIO se použije k vysílání zpráv do oboru názvů.

  6. Vytvořte funkci, která vrátí index.html pro zobrazení.

    1. Vytvořte složku public v části src/.

    2. Vytvořte soubor index.html HTML s následujícím obsahem.

      <html>
      
      <body>
      <h1>Socket.IO Serverless Sample</h1>
      <div id="chatPage" class="chat-container">
          <div class="chat-input">
              <input type="text" id="chatInput" placeholder="Type your message here...">
              <button onclick="sendMessage()">Send</button>
          </div>
          <div id="chatMessages" class="chat-messages"></div>
      </div>
      <script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
      <script>
          function appendMessage(message) {
          const chatMessages = document.getElementById('chatMessages');
          const messageElement = document.createElement('div');
          messageElement.innerText = message;
          chatMessages.appendChild(messageElement);
          hatMessages.scrollTop = chatMessages.scrollHeight;
          }
      
          function sendMessage() {
          const message = document.getElementById('chatInput').value;
          if (message) {
              document.getElementById('chatInput').value = '';
              socket.emit('chat', message);
          }
          }
      
          async function initializeSocket() {
          const negotiateResponse = await fetch(`/api/negotiate`);
          if (!negotiateResponse.ok) {
              console.log("Failed to negotiate, status code =", negotiateResponse.status);
              return;
          }
          const negotiateJson = await negotiateResponse.json();
          socket = io(negotiateJson.endpoint, {
              path: negotiateJson.path,
              query: { access_token: negotiateJson.token }
          });
      
          socket.on('new message', (socketId, message) => {
              appendMessage(`${socketId.substring(0,5)}: ${message}`);
          })
          }
      
          initializeSocket();
      </script>
      </body>
      
      </html>
      
    3. Pokud chcete vrátit stránku HTML, vytvořte funkci a zkopírujte kód:

      func new --template "Http Trigger" --name index
      
    4. Otevřete soubor src/functions/index.js a nahraďte ho následujícím kódem:

      const { app } = require('@azure/functions');
      
      const fs = require('fs').promises;
      const path = require('path')
      
      async function index(request, context) {
          try {
              context.log(`HTTP function processed request for url "${request.url}"`);
      
              const filePath = path.join(__dirname,'../public/index.html');
              const html = await fs.readFile(filePath);
              return {
                  body: html,
                  headers: {
                      'Content-Type': 'text/html'
                  }
              };
          } catch (error) {
              context.log(error);
              return {
                  status: 500,
                  jsonBody: error
              }
          }
      };
      
      app.http('index', {
          methods: ['GET', 'POST'],
          authLevel: 'anonymous',
          handler: index
      });
      
      

Jak aplikaci spustit místně

Jakmile je kód připravený, postupujte podle pokynů ke spuštění ukázky.

Nastavení služby Azure Storage pro funkci Azure Functions

Azure Functions vyžaduje, aby účet úložiště fungoval i v místním prostředí. Zvolte jednu z těchto dvou možností:

  • Spusťte bezplatný emulátor Azurite.
  • Použijte službu Azure Storage. Pokud ho budete dál používat, mohou vám být účtovány náklady.
  1. Nainstalujte Azurite
npm install -g azurite
  1. Spusťte emulátor úložiště Azurite:
azurite -l azurite -d azurite\debug.log
  1. Ujistěte se, že je v AzureWebJobsStoragelocal.settings.json nastavena hodnota UseDevelopmentStorage=true.

Nastavení konfigurace web pubSub pro Socket.IO

  1. Přidejte připojovací řetězec do aplikace funkcí:
func settings add WebPubSubForSocketIOConnectionString "<connection string>"
  1. Přidání nastavení hubu k Web PubSub pro Socket.IO
az webpubsub hub create -n <resource name> -g <resource group> --hub-name hub --event-handler url-template="tunnel:///runtime/webhooks/socketio" user-event-pattern="*"

Připojovací řetězec lze získat příkazem Azure CLI.

az webpubsub key show -g <resource group> -n <resource name>

Výstup obsahuje primaryConnectionString a secondaryConnectionString, a obojí je k dispozici.

Nastavení tunelu

V bezserverovém režimu služba k aktivaci funkce používá webhooky. Když se pokusíte aplikaci spustit místně, zásadním problémem je umožnit službě přístup k vašemu místnímu koncovému bodu funkce.

Nejjednodušší způsob, jak toho dosáhnout, je použít nástroj Tunnel Tool.

  1. Nainstalujte nástroj Tunnel Tool:

    npm install -g @azure/web-pubsub-tunnel-tool
    
  2. Spuštění tunelu

    awps-tunnel run --hub hub --connection "<connection string>" --upstream http://127.0.0.1:7071
    

    Jedná se --upstream o adresu URL, kterou místní funkce Azure Functions zveřejňuje. Port se může lišit a při spuštění funkce v dalším kroku můžete zkontrolovat výstup.

Spuštění ukázkové aplikace

Po spuštění nástroje tunelu můžete aplikaci Function App spustit místně:

func start

A navštivte webovou stránku na http://localhost:7071/api/indexadrese .

Snímek obrazovky bezserverové chatovací aplikace

Další kroky

Dále se můžete pokusit pomocí Bicep nasadit aplikaci online s ověřováním na základě identity: