Delen via


Zelfstudie: Een chat-app bouwen met Azure Function in de serverloze modus (preview)

In deze zelfstudie leert u hoe u een Web PubSub voor Socket.IO-service maakt in de serverloze modus en hoe u een chat-app bouwt die is geïntegreerd met Azure Function.

Zoek volledige codevoorbeelden die in deze zelfstudie worden gebruikt:

Belangrijk

De standaardmodus heeft een permanente server nodig. U kunt Web PubSub niet integreren voor Socket.IO in de standaardmodus met Azure Function.

Belangrijk

De onbewerkte verbindingsreeksen worden in dit artikel uitsluitend voor demonstratiedoeleinden vertoond.

Een verbindingsreeks bevat de autorisatiegegevens die nodig zijn voor uw toepassing voor toegang tot de Azure Web PubSub-service. De toegangssleutel in de verbindingsreeks is vergelijkbaar met een hoofdwachtwoord voor uw service. Beveilig uw toegangssleutels altijd in productieomgevingen. Gebruik Azure Key Vault om uw sleutels veilig te beheren en te roteren en uw verbinding te beveiligen.WebPubSubServiceClient

Vermijd het distribueren van toegangssleutels naar andere gebruikers, het coderen ervan of het opslaan van ze ergens in tekst zonder opmaak die toegankelijk is voor anderen. Draai uw sleutels als u denkt dat ze mogelijk zijn aangetast.

Vereiste voorwaarden

Een Web PubSub maken voor Socket.IO resource in de serverloze modus

Als u een Web PubSub voor Socket.IO wilt maken, kunt u de volgende Azure CLI-opdracht gebruiken:

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

Een Azure Function-project lokaal maken

Volg de stappen om een lokaal Azure Function-project te initiëren.

  1. Volg de stap voor het installeren van het meest recente Azure Function Core-hulpprogramma

  2. Voer in het terminalvenster of vanaf een opdrachtprompt de volgende opdracht uit om een project in de SocketIOProject map te maken:

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

    Met deze opdracht maakt u een JavaScript-project. Voer de map SocketIOProject in om de volgende opdrachten uit te voeren.

  3. Op dit moment bevat de functiebundel geen Socket.IO functiebinding, dus u moet het pakket handmatig toevoegen.

    1. Als u de verwijzing naar de functiebundel wilt elimineren, bewerkt u het bestand host.json en verwijdert u de volgende regels.

      "extensionBundle": {
          "id": "Microsoft.Azure.Functions.ExtensionBundle",
          "version": "[4.*, 5.0.0)"
      }
      
    2. Voer de opdracht uit:

      func extensions install -p Microsoft.Azure.WebJobs.Extensions.WebPubSubForSocketIO -v 1.0.0-beta.4
      
  4. Maak een functie voor onderhandeling. De onderhandelingsfunctie die wordt gebruikt voor het genereren van eindpunten en tokens voor de client voor toegang tot de service.

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

    Open het bestand in src/functions/negotiate.js en vervang het door de volgende 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
    });
    

    Met deze stap maakt u een functie negotiate met HTTP-trigger en SocketIONegotiation uitvoerbinding. Dit betekent dat u een HTTP-aanroep kunt gebruiken om de functie te activeren en een onderhandelingsresultaat te retourneren dat is gegenereerd door SocketIONegotiation binding.

  5. Maak een functie voor het overhandigen van berichten.

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

    Open het bestand src/functions/message.js en vervang het door de volgende 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
    });
    

    Dit gebruikt SocketIOTrigger om geactiveerd te worden door een Socket.IO clientbericht en gebruikt SocketIO binding om berichten naar de namespace uit te zenden.

  6. Maak een functie om een index-HTML te retourneren voor een bezoek.

    1. Maak een map public onder src/.

    2. Maak een HTML-bestand index.html met de volgende inhoud.

      <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. Als u de HTML-pagina wilt retourneren, maakt u een functie en kopieert u codes:

      func new --template "Http Trigger" --name index
      
    4. Open het bestand src/functions/index.js en vervang het door de volgende 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
      });
      
      

De app lokaal uitvoeren

Nadat de code is voorbereid, volgt u de instructies om het voorbeeld uit te voeren.

Azure Storage instellen voor Azure Function

Voor Azure Functions is een opslagaccount vereist om zelfs lokaal te kunnen worden uitgevoerd. Kies een van de twee volgende opties:

  • Voer de gratis Azurite emulator uit.
  • Gebruik de Azure Storage-service. Dit kan kosten met zich meebrengen als u deze blijft gebruiken.
  1. De Azurite installeren
npm install -g azurite
  1. Start de Emulator van de Azurite-opslag:
azurite -l azurite -d azurite\debug.log
  1. Zorg ervoor dat de AzureWebJobsStorage in local.settings.json is ingesteld op UseDevelopmentStorage=true.

Configuratie van Web PubSub instellen voor Socket.IO

  1. Voeg een verbindingsreeks toe aan de Function APP:
func settings add WebPubSubForSocketIOConnectionString "<connection string>"
  1. Hubinstellingen toevoegen aan de Web PubSub voor 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="*"

De verbindingsreeks kan worden verkregen met de Azure CLI-opdracht

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

De uitvoer bevat primaryConnectionString en secondaryConnectionString, en beide zijn beschikbaar.

Tunnel instellen

In de serverloze modus gebruikt de service webhooks om de functie te activeren. Wanneer u de app lokaal probeert uit te voeren, is er een cruciaal probleem waardoor de service geen toegang kan krijgen tot uw lokale functie-eindpunt.

Een eenvoudigste manier om dit te bereiken is door tunnelhulpprogramma te gebruiken

  1. Tunnelhulpprogramma installeren:

    npm install -g @azure/web-pubsub-tunnel-tool
    
  2. De tunnel uitvoeren

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

    Dit --upstream is de URL die de lokale Azure-functie beschikbaar maakt. De poort kan afwijken en u kunt de uitvoer controleren bij het starten van de functie in de volgende stap.

Voorbeeld-app uitvoeren

Nadat het tunnelhulpprogramma is uitgevoerd, kunt u de functieapplicatie lokaal uitvoeren:

func start

En bezoek de webpagina op http://localhost:7071/api/index.

Schermopname van de serverloze chat-app.

Volgende stappen

Vervolgens kunt u Bicep gebruiken om de app online te implementeren met verificatie op basis van identiteit: