Udostępnij za pomocą


Samouczek: tworzenie aplikacji czatu za pomocą funkcji platformy Azure w trybie bezserwerowym (wersja zapoznawcza)

W tym samouczku przedstawiono sposób tworzenia usługi Web PubSub dla usługi Socket.IO w trybie bezserwerowym i tworzenia aplikacji czatu integrującej się z funkcją platformy Azure.

Znajdź pełne przykłady kodu używane w tym samouczku:

Ważne

Tryb domyślny wymaga trwałego serwera. Nie można zintegrować usługi Web PubSub dla Socket.IO w trybie domyślnym z funkcją platformy Azure.

Ważne

Nieprzetworzone parametry połączenia są wyświetlane tylko w tym artykule w celach demonstracyjnych.

Parametry połączenia zawiera informacje o autoryzacji wymagane przez aplikację w celu uzyskania dostępu do usługi Azure Web PubSub. Klucz dostępu wewnątrz ciągu połączenia jest podobny do hasła głównego dla twojej usługi. W środowiskach produkcyjnych zawsze chroń klucze dostępu. Użyj usługi Azure Key Vault, aby bezpiecznie zarządzać kluczami i obracać je oraz zabezpieczać połączenie za pomocą usługi WebPubSubServiceClient.

Unikaj dystrybuowania kluczy dostępu do innych użytkowników, kodowania ich lub zapisywania ich w dowolnym miejscu w postaci zwykłego tekstu, który jest dostępny dla innych użytkowników. Obróć klucze, jeśli uważasz, że zostały naruszone.

Wymagania wstępne

Tworzenie usługi Web PubSub dla zasobu Socket.IO w trybie bezserwerowym

Aby utworzyć usługę Web PubSub dla Socket.IO, możesz użyć następującego polecenia interfejsu wiersza polecenia platformy Azure:

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

Lokalne tworzenie projektu funkcji platformy Azure

Należy wykonać kroki, aby zainicjować lokalny projekt funkcji platformy Azure.

  1. Wykonaj kroki, aby zainstalować najnowsze narzędzie podstawowe funkcji platformy Azure

  2. W oknie terminalu lub w wierszu polecenia uruchom następujące polecenie, aby utworzyć projekt w folderze SocketIOProject :

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

    To polecenie tworzy projekt JavaScript. Wprowadź folder SocketIOProject , aby uruchomić następujące polecenia.

  3. Obecnie pakiet funkcji nie zawiera Socket.IO powiązania funkcji, dlatego należy ręcznie dodać pakiet.

    1. Aby wyeliminować odwołanie do pakietu funkcji, zmodyfikuj plik host.json i usuń następujące wiersze.

      "extensionBundle": {
          "id": "Microsoft.Azure.Functions.ExtensionBundle",
          "version": "[4.*, 5.0.0)"
      }
      
    2. Uruchom polecenie:

      func extensions install -p Microsoft.Azure.WebJobs.Extensions.WebPubSubForSocketIO -v 1.0.0-beta.4
      
  4. Utwórz funkcję na potrzeby negocjacji. Funkcja negocjacji używana do generowania punktów końcowych i tokenów dla klienta w celu uzyskania dostępu do usługi.

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

    Otwórz plik w src/functions/negotiate.js pliku i zastąp go następującym kodem:

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

    Ten krok tworzy funkcję negotiate z wyzwalaczem HTTP i powiązaniem wyjściowym SocketIONegotiation, co oznacza, że można użyć wywołania HTTP, aby wyzwolić funkcję i zwrócić wynik negocjacji generowany przez powiązanie SocketIONegotiation.

  5. Utwórz funkcję do przekazywania komunikatów.

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

    Otwórz plik src/functions/message.js i zastąp ciąg następującym kodem:

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

    Służy SocketIOTrigger do wyzwalania przez komunikat klienta Socket.IO i używania SocketIO powiązania do emisji komunikatów w przestrzeni nazw.

  6. Utwórz funkcję, aby zwrócić kod HTML indeksu na potrzeby odwiedzania.

    1. Utwórz folder public w obszarze src/.

    2. Utwórz plik index.html HTML z następującą zawartością.

      <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. Aby zwrócić stronę HTML, utwórz funkcję i kody kopiowania:

      func new --template "Http Trigger" --name index
      
    4. Otwórz plik src/functions/index.js i zastąp ciąg następującym kodem:

      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 uruchomić aplikację lokalnie

Po przygotowaniu kodu wykonaj instrukcje uruchamiania przykładu.

Konfigurowanie usługi Azure Storage dla funkcji platformy Azure

Usługa Azure Functions wymaga, aby konto magazynu działało nawet lokalnie. Wybierz jedną z dwóch następujących opcji:

  • Uruchom bezpłatny emulator Azurite.
  • Użyj usługi Azure Storage. Może to wiązać się z kosztami, jeśli będzie on nadal używany.
  1. Instalowanie Azurite
npm install -g azurite
  1. Uruchom emulator magazynu Azurite:
azurite -l azurite -d azurite\debug.log
  1. Upewnij się, że AzureWebJobsStorage w local.settings.json ustawiono UseDevelopmentStorage=truewartość .

Konfigurowanie konfiguracji usługi Web PubSub dla Socket.IO

  1. Dodaj parametry połączenia do aplikacji funkcji:
func settings add WebPubSubForSocketIOConnectionString "<connection string>"
  1. Dodawanie ustawień centrum do usługi Web PubSub dla 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="*"

Parametry połączenia można uzyskać za pomocą polecenia interfejsu wiersza polecenia platformy Azure

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

Dane wyjściowe zawierają primaryConnectionString wartości i secondaryConnectionString, i są dostępne.

Konfigurowanie tunelu

W trybie bezserwerowym usługa używa elementów webhook do wyzwalania funkcji. Podczas próby uruchomienia aplikacji lokalnie kluczowy problem polega na tym, że usługa będzie mogła uzyskać dostęp do lokalnego punktu końcowego funkcji.

Najprostszym sposobem osiągnięcia tego celu jest użycie narzędzia Tunnel Tool

  1. Zainstaluj narzędzie tunelu:

    npm install -g @azure/web-pubsub-tunnel-tool
    
  2. Uruchamianie tunelu

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

    Jest --upstream to adres URL, który uwidacznia lokalna funkcja platformy Azure. Port może być inny i można sprawdzić dane wyjściowe podczas uruchamiania funkcji w następnym kroku.

Uruchamianie przykładowej aplikacji

Po uruchomieniu narzędzia tunelu możesz uruchomić aplikację funkcji lokalnie:

func start

Odwiedź stronę internetową pod adresem http://localhost:7071/api/index.

Zrzut ekranu przedstawiający aplikację do czatu bezserwerowego.

Następne kroki

Następnie możesz spróbować użyć aplikacji Bicep do wdrożenia aplikacji w trybie online przy użyciu uwierzytelniania opartego na tożsamościach: