Freigeben über


Tutorial: Erstellen einer Chat-App mit Azure Function im serverlosen Modus (Vorschau)

In diesem Tutorial erfahren Sie, wie Sie einen Web PubSub für Socket.IO-Dienst im serverlosen Modus erstellen und eine Chat-App erstellen, die in Azure Function integriert ist.

Finden Sie vollständige Codebeispiele, die in diesem Tutorial verwendet werden:

Wichtig

Der Standardmodus benötigt einen beständigen Server. Web PubSub für Socket.IO kann nicht im Standardmodus mit Azure Function integriert werden.

Wichtig

Unformatierte Verbindungszeichenfolgen werden in diesem Artikel nur zu Demonstrationszwecken angezeigt.

Eine Verbindungszeichenfolge enthält die Autorisierungsinformationen, die Ihre Anwendung für den Zugriff auf den Azure Web PubSub-Dienst benötigt. Der Zugriffsschlüssel in der Verbindungszeichenfolge ähnelt einem Stammkennwort für Ihren Dienst. Schützen Sie Ihre Zugriffsschlüssel in Produktionsumgebungen immer sorgfältig. Verwenden Sie Azure Key Vault zum sicheren Verwalten und Rotieren Ihrer Schlüssel und zum Schützen Ihrer Verbindung mit WebPubSubServiceClient.

Geben Sie Zugriffsschlüssel nicht an andere Benutzer weiter, vermeiden Sie das Hartcodieren, und speichern Sie die Schlüssel nicht als Klartext, auf den andere Benutzer Zugriff haben. Rotieren Sie die Schlüssel, wenn Sie glauben, dass sie möglicherweise gefährdet sind.

Voraussetzungen

Erstellen einer Web PubSub für Socket.IO-Ressource im serverlosen Modus

Um ein Web PubSub für Socket.IO zu erstellen, können Sie den folgenden Azure CLI-Befehl verwenden:

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

Lokales Erstellen eines Azure Function-Projekts

Führen Sie die Schritte aus, um ein lokales Azure Function-Projekt zu initiieren.

  1. Sie sollten die Schritte ausführen, um das neueste Azure Function Core Tool zu installieren

  2. Führen Sie im Terminalfenster oder an einer Eingabeaufforderung den folgenden Befehl aus, um ein Projekt im Ordner SocketIOProject zu erstellen:

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

    Mit diesem Befehl wird ein JavaScript-Projekt erstellt. Und geben Sie den Ordner SocketIOProject ein, um die folgenden Befehle auszuführen.

  3. Derzeit enthält das Function-Bundle nicht die Function-Bindung für Socket.IO, daher müssen Sie das Paket manuell hinzufügen.

    1. Um den Function-Bundle-Verweis zu beseitigen, bearbeiten Sie die host.json-Datei, und entfernen Sie die folgenden Zeilen.

      "extensionBundle": {
          "id": "Microsoft.Azure.Functions.ExtensionBundle",
          "version": "[4.*, 5.0.0)"
      }
      
    2. Ausführen des Befehls:

      func extensions install -p Microsoft.Azure.WebJobs.Extensions.WebPubSubForSocketIO -v 1.0.0-beta.4
      
  4. Erstellen Sie eine Funktion für die Aushandlung. Die Aushandlungsfunktion, die zum Generieren von Endpunkten und Token verwendet wird, damit der Client auf den Dienst zugreifen kann.

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

    Öffnen Sie die Datei in src/functions/negotiate.js, und ersetzen Sie sie durch den folgenden Code:

    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
    });
    

    Dieser Schritt erstellt eine Funktion negotiate mit HTTP-Trigger und SocketIONegotiation Ausgabebindung, was bedeutet, dass Sie einen HTTP-Aufruf verwenden können, um die Funktion auszulösen und ein Aushandlungsergebnis zurückzugeben, das durch SocketIONegotiation Bindung generiert wurde.

  5. Erstellen Sie eine Funktion zum Übergeben von Nachrichten.

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

    Öffnen Sie die Datei src/functions/message.js, und ersetzen Sie sie durch den folgenden Code:

    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
    });
    

    Dieser verwendet SocketIOTrigger, um von einer Clientnachricht für Socket.IO ausgelöst zu werden und eine SocketIO-Bindung zum Übertragen von Nachrichten in den Namespace zu verwenden.

  6. Erstellen Sie eine Funktion, um eine index.html-Datei für den Besuch zurückzugeben.

    1. Erstellen Sie unter public einen src/-Ordner.

    2. Erstellen Sie eine index.html-HTML-Datei mit dem folgenden Inhalt.

      <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. Um die HTML-Seite zurückzugeben, erstellen Sie eine Funktion, und kopieren Sie Codes:

      func new --template "Http Trigger" --name index
      
    4. Öffnen Sie die Datei src/functions/index.js, und ersetzen Sie sie durch den folgenden Code:

      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
      });
      
      

Lokales Ausführen der App

Nachdem Code vorbereitet wurde, folgen Sie den Anweisungen zum Ausführen des Beispiels.

Einrichten von Azure Storage für Azure Function

Für Azure Functions ist ein Speicherkonto erforderlich, auch bei lokalen Ausführungen. Wählen Sie eine der beiden folgenden Optionen aus:

  • Führen Sie den kostenlosen Azurite-Emulator aus.
  • Verwenden des Azure Storage-Diensts. Dadurch können Kosten anfallen, wenn Sie ihn weiterhin verwenden.
  1. Installieren Sie den Azurite-Emulator
npm install -g azurite
  1. Starten Sie den Azurite-Speicheremulator:
azurite -l azurite -d azurite\debug.log
  1. Stellen Sie sicher, dass AzureWebJobsStorage in local.settings.json auf UseDevelopmentStorage=true festgelegt ist.

Einrichten der Konfiguration von Web PubSub für Socket.IO

  1. Fügen Sie der Funktions-APP eine Verbindungszeichenfolge hinzu:
func settings add WebPubSubForSocketIOConnectionString "<connection string>"
  1. Fügen Sie Web PubSub für Socket.IO Hubeinstellungen hinzu
az webpubsub hub create -n <resource name> -g <resource group> --hub-name hub --event-handler url-template="tunnel:///runtime/webhooks/socketio" user-event-pattern="*"

Die Verbindungszeichenfolge kann vom Azure CLI-Befehl abgerufen werden

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

Die Ausgabe enthält primaryConnectionString und secondaryConnectionString, und beide sind verfügbar.

Einrichten eines Tunnels

Im serverlosen Modus verwendet der Dienst Webhooks, um die Funktion auszulösen. Wenn Sie versuchen, die App lokal auszuführen, besteht ein entscheidendes Problem darin, dem Dienst zu ermöglichen, auf Ihren lokalen Funktionsendpunkt zuzugreifen.

Die einfachste Möglichkeit, um dies zu erreichen, ist, das Tunneltool zu verwenden

  1. Installieren Sie das Tunneltool:

    npm install -g @azure/web-pubsub-tunnel-tool
    
  2. Führen Sie den Tunnel aus

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

    --upstream ist die URL, die die lokale Azure-Funktion verfügbar macht. Möglicherweise ist der Port anders, und Sie können die Ausgabe überprüfen, wenn Sie die Funktion im nächsten Schritt starten.

Ausführen einer Beispiel-App

Nachdem das Tunneltool ausgeführt wurde, können Sie die Funktions-App lokal ausführen:

func start

Und besuchen Sie die Webseite unter http://localhost:7071/api/index.

Screenshot der serverlosen Chat-App.

Nächste Schritte

Als Nächstes können Sie versuchen, Bicep zu verwenden, um die App online mit identitätsbasierter Authentifizierung bereitzustellen: