分享方式:


教學課程:使用 Azure Functions 和 Azure Web PubSub 服務建立無伺服器通知應用程式

Azure Web PubSub 服務可協助您使用 WebSocket 建置即時傳訊 Web 應用程式。 Azure Functions 是無伺服器平台,可讓您在不需要管理任何基礎結構的情況下執行您的程式碼。 在本教學課程中,您會了解如何使用 Azure Web PubSub 服務和 Azure Functions,在通知案例下建置具有即時傳訊的無伺服器應用程式。

在本教學課程中,您會了解如何:

  • 建置無伺服器通知應用程式
  • 使用 Web PubSub 函式輸入和輸出繫結
  • 在本機執行範例函式
  • 將函式部署至 Azure 函數應用程式

必要條件

如果您沒有 Azure 訂用帳戶,請在開始之前先建立 Azure 免費帳戶

登入 Azure

請使用您的 Azure 帳戶登入 Azure 入口網站 (https://portal.azure.com/)。

建立 Azure Web PubSub 服務執行個體

您的應用程式將會連線至 Azure 中的 Web PubSub 服務執行個體。

  1. 選取 Azure 入口網站左上角的 [新增] 按鈕。 在 [新增] 畫面的搜尋方塊中輸入 Web PubSub 並按 Enter。 (您也可以從 Web 類別搜尋 Azure Web PubSub。)

    Screenshot of searching the Azure Web PubSub in portal.

  2. 從搜尋結果中選取 [Web PubSub],然後選取 [建立]

  3. 輸入下列設定。

    設定 建議的值 描述
    資源名稱 全域唯一的名稱 識別新 Web PubSub 服務執行個體的全域唯一名稱。 有效字元:a-zA-Z0-9-
    訂用帳戶 您的訂用帳戶 將在其下建立這個新 Web PubSub 服務執行個體的 Azure 訂用帳戶。
    資源群組 myResourceGroup 要在其中建立 Web PubSub 服務執行個體之新資源群組的名稱。
    地點 美國西部 選擇您附近的區域
    定價層 免費 您可以先免費試用 Azure Web PubSub 服務。 深入了解 Azure Web PubSub 服務定價層
    單位計數 - 單位計數會指出您的 Web PubSub 服務執行個體可接受的連線數目。 每個單位支援最多 1,000 個同時連線。 它只能在標準層中設定。

    Screenshot of creating the Azure Web PubSub instance in portal.

  4. 選取 [建立] 以開始部署 Web PubSub 服務執行個體。

在本機建立及執行函式

  1. 請確定您已安裝 Azure Functions Core Tools。 現在,請為專案建立空的目錄。 在此工作目錄下執行命令。 使用下列其中一個指定選項。

    func init --worker-runtime javascript --model V4
    
  2. 請遵循步驟來安裝 Microsoft.Azure.WebJobs.Extensions.WebPubSub

    確認或將 host.json 的 extensionBundle 更新為 4.* 版或更新版本,以取得 Web PubSub 支援。 若要更新 host.json,請在編輯器中開啟檔案,然後將現有的版本 extensionBundle 取代為 4.* 版或更新版本。

    {
        "extensionBundle": {
            "id": "Microsoft.Azure.Functions.ExtensionBundle",
            "version": "[4.*, 5.0.0)"
        }
    }
    
  3. 建立 index 函式,以讀取和裝載用戶端的靜態網頁。

    func new -n index -t HttpTrigger
    
    • 更新 src/functions/index.js 並複製下列程式碼。
      const { app } = require('@azure/functions');
      const { readFile } = require('fs/promises');
      
      app.http('index', {
          methods: ['GET', 'POST'],
          authLevel: 'anonymous',
          handler: async (context) => {
              const content = await readFile('index.html', 'utf8', (err, data) => {
                  if (err) {
                      context.err(err)
                      return
                  }
              });
      
              return { 
                  status: 200,
                  headers: { 
                      'Content-Type': 'text/html'
                  }, 
                  body: content, 
              };
          }
      });
      
  4. 建立 negotiate 函式,協助用戶端使用存取權杖取得服務連線 URL。

    func new -n negotiate -t HttpTrigger
    
    • 更新 src/functions/negotiate.js 並複製下列程式碼。
      const { app, input } = require('@azure/functions');
      
      const connection = input.generic({
          type: 'webPubSubConnection',
          name: 'connection',
          hub: 'notification'
      });
      
      app.http('negotiate', {
          methods: ['GET', 'POST'],
          authLevel: 'anonymous',
          extraInputs: [connection],
          handler: async (request, context) => {
              return { body: JSON.stringify(context.extraInputs.get('connection')) };
          },
      });
      
  5. 使用 TimerTrigger 建立 notification 函式來產生通知。

    func new -n notification -t TimerTrigger
    
    • 更新 src/functions/notification.js 並複製下列程式碼。
      const { app, output } = require('@azure/functions');
      
      const wpsAction = output.generic({
          type: 'webPubSub',
          name: 'action',
          hub: 'notification'
      });
      
      app.timer('notification', {
          schedule: "*/10 * * * * *",
          extraOutputs: [wpsAction],
          handler: (myTimer, context) => {
              context.extraOutputs.set(wpsAction, {
                  actionName: 'sendToAll',
                  data: `[DateTime: ${new Date()}] Temperature: ${getValue(22, 1)}\xB0C, Humidity: ${getValue(40, 2)}%`,
                  dataType: 'text',
              });
          },
      });
      
      function getValue(baseNum, floatNum) {
          return (baseNum + 2 * floatNum * (Math.random() - 0.5)).toFixed(3);
      }
      
  6. 在專案根資料夾中新增用戶端單一頁面 index.html 並複製內容。

    <html>
        <body>
        <h1>Azure Web PubSub Notification</h1>
        <div id="messages"></div>
        <script>
            (async function () {
                let messages = document.querySelector('#messages');
                let res = await fetch(`${window.location.origin}/api/negotiate`);
                let url = await res.json();
                let ws = new WebSocket(url.url);
                ws.onopen = () => console.log('connected');
    
                ws.onmessage = event => {
                    let m = document.createElement('p');
                    m.innerText = event.data;
                    messages.appendChild(m);
                };
            })();
        </script>
        </body>
    </html>
    
  7. 設定及執行 Azure Function 應用程式

    • 在瀏覽器中,開啟 Azure 入口網站,並確認您稍早部署的 Web PubSub 服務執行個體已成功建立。 瀏覽至執行個體。
    • 選取 [金鑰] 並複製連接字串。

    Screenshot of copying the Web PubSub connection string.

    在函式資料夾中執行命令,以設定服務連接字串。 視需要使用您的值取代 <connection-string>

    func settings add WebPubSubConnectionString "<connection-string>"
    

    注意

    範例中使用的 TimerTrigger 函式相依於 Azure 儲存體,但您可以在函式於本機執行時使用本機儲存體模擬器。 如果您收到 There was an error performing a read operation on the Blob Storage Secret Repository. Please ensure the 'AzureWebJobsStorage' connection string is valid. 之類的錯誤,您必須下載並啟用儲存體模擬器

    現在您可以透過命令執行本機函式。

    func start --port 7071
    

    若要檢查正在執行的記錄,可以透過造訪 http://localhost:7071/api/index 頁面來造訪本機主機靜態頁面。

    注意

    有些瀏覽器會自動重新導向至 https,從而導致錯誤的 URL。 建議使用 Edge,並在轉譯不成功時再次檢查 URL。

將函數應用程式部署至 Azure

若要將函式程式碼部署至 Azure,您必須先建立三個資源:

  • 資源群組,其為相關資源的邏輯容器。
  • 儲存體帳戶,用來維護函式的狀態和其他資訊。
  • 函數應用程式,其提供執行函式程式碼的環境。 函數應用程式可對應至您的本機函式專案,並可讓您將函式分組為邏輯單位,以便管理、部署和共用資源。

請使用下列命令來建立這些項目。

  1. 登入 Azure:

    az login
    
  2. 建立資源群組,或者您可以重複使用其中一個 Azure Web PubSub 服務來略過:

    az group create -n WebPubSubFunction -l <REGION>
    
  3. 在您的資源群組和區域中建立一般用途的儲存體帳戶:

    az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
    
  4. 在 Azure 中建立函式應用程式:

    az functionapp create --resource-group WebPubSubFunction --consumption-plan-location <REGION> --runtime node --runtime-version 18 --functions-version 4 --name <FUNCIONAPP_NAME> --storage-account <STORAGE_NAME>
    

    注意

    請參閱 Azure Functions 執行階段版本文件,將 --runtime-version 參數設定為支援的值。

  5. 將函式專案部署至 Azure

    在 Azure 中建立函數應用程式之後,您就可以開始使用 func azure functionapp publish 命令來部署本機函式專案。

    func azure functionapp publish <FUNCIONAPP_NAME> --publish-local-settings
    

    注意

    在這裡,我們會將本機設定 local.settings.json 與命令參數 --publish-local-settings 一起進行部署。 如果您使用 Microsoft Azure 儲存體模擬器,則您可以輸入 no 以略過在 Azure 上覆寫此值的提示訊息:App setting AzureWebJobsStorage is different between azure and local.settings.json, Would you like to overwrite value in azure? [yes/no/show]。 此外,您也可以在 Azure 入口網站 -> [設定] -> [組態] 中更新函數應用程式設定。

  6. 現在,您可以透過瀏覽至 URL,從 Azure 函數應用程式檢查您的網站: https://<FUNCIONAPP_NAME>.azurewebsites.net/api/index

清除資源

如果您不會繼續使用此應用程式,請使用下列步驟來刪除本文件所建立的全部資源,這樣才不會產生任何費用:

  1. 在 Azure 入口網站中選取最左側的 [資源群組],然後選取您所建立的資源群組。 使用搜尋方塊,改為依資源群組的名稱尋找。

  2. 在開啟的視窗中選取資源群組,然後選取 [刪除資源群組]

  3. 在新視窗中輸入要刪除的資源群組名稱,然後選取 [刪除]

下一步

在本快速入門中,您已了解如何執行無伺服器聊天應用程式。 現在,您可以開始建置自己的應用程式。