Bagikan melalui


Tutorial: Membangun aplikasi obrolan dengan Azure Function dalam Mode Tanpa Server (Pratinjau)

Tutorial ini memandu Anda melalui cara membuat layanan Web PubSub untuk Socket.IO dalam Mode Tanpa Server dan membangun aplikasi obrolan yang terintegrasi dengan Azure Functions.

Temukan sampel kode lengkap yang digunakan dalam tutorial ini:

Penting

Mode Default memerlukan server persisten, Anda tidak dapat mengintegrasi Web PubSub untuk Socket.IO dalam mode default dengan Azure Function.

Penting

String koneksi mentah ditampilkan dalam artikel ini hanya untuk tujuan demonstrasi.

String koneksi menyertakan informasi otorisasi yang diperlukan agar aplikasi Anda mengakses layanan Azure Web PubSub. Kunci akses di dalam string koneksi mirip dengan kata sandi root untuk layanan Anda. Di lingkungan produksi, selalu lindungi kunci akses Anda. Gunakan Azure Key Vault untuk mengelola dan memutar kunci Anda dengan aman dan mengamankan koneksi Anda dengan WebPubSubServiceClient.

Hindari mendistribusikan kunci akses ke pengguna lain, melakukan hard-coding, atau menyimpannya di mana saja dalam teks biasa yang dapat diakses orang lain. Putar kunci Anda jika Anda yakin bahwa kunci tersebut mungkin telah disusupi.

Prasyarat

Membuat Web PubSub untuk sumber daya Socket.IO dalam Mode Tanpa Server

Untuk membuat Web PubSub untuk Socket.IO, Anda bisa menggunakan perintah Azure CLI berikut:

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

Membuat proyek Azure Function secara lokal

Anda harus mengikuti langkah-langkah untuk memulai proyek Azure Function lokal.

  1. Ikuti langkah untuk menginstal alat inti Azure Function terbaru

  2. Di jendela terminal atau dari prompt perintah, jalankan perintah berikut untuk membuat proyek di SocketIOProject folder:

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

    Perintah ini membuat proyek JavaScript. Dan masukkan folder SocketIOProject untuk menjalankan perintah berikut.

  3. Saat ini, Function Bundle tidak menyertakan Socket.IO Function Binding, jadi Anda perlu menambahkan paket secara manual.

    1. Untuk menghilangkan referensi bundel fungsi, edit file host.json dan hapus baris berikut.

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

      func extensions install -p Microsoft.Azure.WebJobs.Extensions.WebPubSubForSocketIO -v 1.0.0-beta.4
      
  4. Buat fungsi untuk negosiasi. Fungsi negosiasi yang digunakan untuk menghasilkan titik akhir dan token bagi klien untuk mengakses layanan.

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

    Buka file di src/functions/negotiate.js dan ganti dengan kode berikut:

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

    Langkah ini membuat fungsi negotiate dengan Pemicu HTTP dan pengikatan output SocketIONegotiation, yang berarti Anda dapat menggunakan panggilan HTTP untuk memicu fungsi dan mengembalikan hasil negosiasi yang dihasilkan oleh pengikatan SocketIONegotiation.

  5. Buat fungsi untuk menyerahkan pesan.

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

    Buka file src/functions/message.js dan ganti dengan kode berikut:

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

    Ini menggunakan SocketIOTrigger untuk dipicu oleh pesan klien Socket.IO dan menggunakan SocketIO binding untuk menyiarkan pesan ke ruang lingkup namespace.

  6. Buat fungsi untuk menghasilkan halaman HTML indeks untuk dikunjungi.

    1. Buat folder public di bawah src/.

    2. Buat file index.html html dengan konten berikut.

      <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. Untuk mengembalikan halaman HTML, buat fungsi dan salin kode:

      func new --template "Http Trigger" --name index
      
    4. Buka file src/functions/index.js dan ganti dengan kode berikut:

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

Cara menjalankan Aplikasi secara lokal

Setelah kode disiapkan, ikuti instruksi untuk menjalankan sampel.

Siapkan Azure Storage untuk Fungsi Azure.

Azure Functions memerlukan akun penyimpanan untuk berfungsi bahkan ketika berjalan secara lokal. Pilih salah satu dari dua opsi berikut:

  • Jalankan emulator Azurite gratis.
  • Gunakan layanan Azure Storage. Ini mungkin dikenakan biaya jika Anda terus menggunakannya.
  1. Pemasangan Program Azurite
npm install -g azurite
  1. Mulai emulator penyimpanan Azurite:
azurite -l azurite -d azurite\debug.log
  1. Pastikan AzureWebJobsStorage dalam local.settings.json diatur ke UseDevelopmentStorage=true.

Menyiapkan konfigurasi Web PubSub untuk Socket.IO

  1. Tambahkan string koneksi ke Aplikasi Fungsi:
func settings add WebPubSubForSocketIOConnectionString "<connection string>"
  1. Menambahkan pengaturan hub ke Web PubSub untuk 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="*"

string koneksi dapat diperoleh oleh perintah Azure CLI

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

Output berisi primaryConnectionString dan secondaryConnectionString, dan salah satu tersedia.

Menyiapkan terowongan

Dalam mode tanpa server, layanan menggunakan webhook untuk memicu fungsi. Ketika Anda mencoba menjalankan aplikasi secara lokal, masalah penting adalah membiarkan layanan dapat mengakses titik akhir fungsi lokal Anda.

Cara termampu untuk mencapainya adalah dengan menggunakan Tunnel Tool

  1. Pasang Alat Tunnel:

    npm install -g @azure/web-pubsub-tunnel-tool
    
  2. Jalankan terowongan

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

    --upstream adalah URL yang diekspos oleh Azure Function lokal. Port mungkin berbeda dan Anda dapat memeriksa output saat memulai fungsi di langkah berikutnya.

Jalankan Aplikasi Sampel

Setelah alat terowongan berjalan, Anda dapat menjalankan Aplikasi Fungsi secara lokal:

func start

Dan kunjungi halaman web di http://localhost:7071/api/index.

Cuplikan layar aplikasi obrolan tanpa server.

Langkah berikutnya

Selanjutnya, Anda dapat mencoba menggunakan Bicep untuk menyebarkan aplikasi secara online dengan autentikasi berbasis identitas: