快速入門:在 Python 中使用 Azure Functions 和 Azure SignalR Service 建立無伺服器應用程式
使用 Azure Functions 和 Python 開始使用 Azure SignalR Service,以建置可將訊息廣播至用戶端的無伺服器應用程式。 您將在本機環境中執行函式,以連線到雲端的 Azure SignalR Service 執行個體。 完成本快速入門後,您的 Azure 帳戶中會產生幾美分或更少的費用。
注意
您可以從 GitHub 取得本文中的程式碼。
重要
原始 連接字串 只會出現在本文中,僅供示範之用。
連接字串 包含應用程式存取 Azure SignalR Service 所需的授權資訊。 連接字串內的存取金鑰類似於服務的根密碼。 在生產環境中,請一律保護您的存取金鑰。 使用 Azure 金鑰保存庫,使用 Microsoft Entra 識別碼安全地管理及輪替密鑰,並保護您的 連接字串,並使用 Microsoft Entra 識別符授權存取權。
避免將存取金鑰散發給其他使用者、寫入程式碼,或將其以純文字儲存在他人可以存取的位置。 如果您認為金鑰可能已遭盜用,請輪替金鑰。
必要條件
此快速入門可以在 macOS、Windows 或 Linux 上執行。 您將需要下列項目:
必要條件 | 描述 |
---|---|
Azure 訂用帳戶 | 如果您沒有 Azure 訂用帳戶,請建立 Azure 免費帳戶。 |
程式碼編輯器 | 您需要程式碼編輯器,例如 Visual Studio Code。 |
Azure Functions Core Tools | 需要 2.7.1505 版或更高版本,才能在本機執行 Python Azure Function 應用程式。 |
Python 3.7+ | Azure Functions 需要 Python 3.7+。 請參閱支援的 Python 版本。 |
Azurite | SignalR 繫結需要 Azure 儲存體。 當函式在本機執行時,您可以使用本機儲存體模擬器。 |
Azure CLI | 您可以選擇性地使用 Azure CLI 來建立 Azure SignalR Service 執行個體。 |
建立 Azure SignalR 服務執行個體
在本節中,您會建立基本 Azure SignalR 執行個體,以用於您的應用程式。 下列步驟會使用 Azure 入口網站來建立新的執行個體,但您也可以使用 Azure CLI。 如需詳細資訊,請參閱 Azure SignalR Service CLI 參考中的 az signalr create 命令。
- 登入 Azure 入口網站。
- 在頁面的左側,選取 [+ 建立資源]。
- 在 [建立資源] 頁面上的 [搜尋服務和市集] 文字方塊中,輸入 signalr,然後從清單中選取 [SignalR Service]。
- 在 [SignalR Service] 頁面上,選取 [建立]。
- 在 [基本] 索引標籤上,您需要輸入新 SignalR Service 執行個體的重要資訊。 輸入下列值:
欄位 | 建議的值 | 描述 |
---|---|---|
訂用帳戶 | 選擇您的訂用帳戶 | 選取您要用來建立新 SignalR Service 執行個體的訂用帳戶。 |
資源群組 | 建立名為 SignalRTestResources 的新資源群組 | 選取或建立 SignalR 資源的資源群組。 針對本教學課程建立新的資源群組,而不是使用現有的資源群組,會很有用。 若要在完成本教學課程之後釋出資源,請刪除資源群組。 刪除資源群組同時會刪除群組所屬的所有資源。 此動作無法復原。 刪除資源群組之前,請確定其不包含您想要保留的資源。 如需詳細資訊,請參閱 使用資源群組來管理您的 Azure 資源。 |
資源名稱 | testsignalr | 輸入要對 SignalR 資源使用的唯一資源名稱。 如果您的區域中已採用 testsignalr,請新增數字或字元,直到成為唯一的名稱為止。 名稱必須是 1 到 63 個字元的字串,而且只能包含數字、字母和連字號 ( - ) 字元。 名稱的開頭或結尾不能是連字號字元,且連續連字號字元無效。 |
區域 | 選擇您的區域 | 選取新 SignalR Service 執行個體的適當區域。 Azure SignalR Service 目前不適用於所有區域。 如需詳細資訊,請參閱 Azure SignalR 區域可用性 |
定價層 | 選取 [變更],然後選擇 [免費 (僅限開發/測試)]。 選擇 [選取] 來確認您選擇的定價層。 | Azure SignalR Service 有三個定價層:免費、標準和進階。 除非必要條件中另有說明,否則教學課程會使用 [免費] 層。 如需有關階層與定價之間功能差異的詳細資訊,請參閱 Azure SignalR Service 定價 |
服務模式 | 選擇適當的服務模式 | 當您在 Web 應用程式中裝載 SignalR 中樞邏輯並使用 SignalR Service 做為 Proxy 時,請使用 [預設值]。 當您使用 Azure Functions 之類的無伺服器技術來裝載 SignalR 中樞邏輯時,請使用 [無伺服器]。 [傳統] 模式僅適用於回溯相容性,不建議使用。 如需詳細資訊,請參閱 Azure SignalR Service 中的服務模式。 |
您不需要針對 SignalR 教學課程變更 [網路] 和 [標籤] 索引標籤上的設定。
- 選取 [基本] 索引標籤底部的 [檢閱 + 建立] 按鈕。
- 在 [檢閱 + 建立] 索引標籤上,檢閱這些值,然後選取 [建立]。 需要數分鐘才能完成部署。
- 部署完成後,請選取 [移至資源] 按鈕。
- 在 SignalR 資源頁面上,從左側功能表的 [設定] 底下選取 [金鑰]。
- 複製主索引鍵的 [連接字串]。 稍後在本教學課程中,您需要此連接字串來設定您的應用程式。
建立 Azure Function 專案
建立本機 Azure Function 專案。
- 從命令列為專案建立目錄。
- 變更為專案目錄。
- 使用 Azure Functions
func init
命令來初始化函式專案。
# Initialize a function project
func init --worker-runtime python
建立函式
初始化專案之後,您必須建立函式。 此專案需要三個函式:
index
:裝載用戶端的網頁。negotiate
:允許用戶端取得存取權杖。broadcast
:使用時間觸發程序定期將訊息廣播到所有用戶端。
當您從專案的根目錄執行 func new
命令時,Azure Functions Core Tools 會在 檔案中 function_app.py
附加函式程式代碼。 您將視需要編輯參數廣告內容,方法是將預設程式代碼取代為應用程式程式代碼。
建立索引函式
您可使用此範例函式作為您自己函式的範本。
開啟 function_app.py
檔案。 此檔案將包含您的函式。 首先,修改 檔案以包含必要的匯入語句,並定義我們將使用於下列函式中的全域變數。
import azure.functions as func
import os
import requests
import json
app = func.FunctionApp()
etag = ''
start_count = 0
- 新增下列程式代碼以新增 函
index
式
@app.route(route="index", auth_level=func.AuthLevel.ANONYMOUS)
def index(req: func.HttpRequest) -> func.HttpResponse:
f = open(os.path.dirname(os.path.realpath(__file__)) + '/content/index.html')
return func.HttpResponse(f.read(), mimetype='text/html')
此函式會裝載用戶端的網頁。
建立交涉函式
新增下列程式代碼以新增 函 negotiate
式。
原始 連接字串 只針對示範目的出現在本文中。 在生產環境中,請一律保護您的存取金鑰。 使用 Azure 金鑰保存庫,使用 Microsoft Entra 識別元安全地管理及輪替您的 連接字串,並使用 Microsoft Entra 標識符來授權存取權。
@app.route(route="negotiate", auth_level=func.AuthLevel.ANONYMOUS, methods=["POST"])
@app.generic_input_binding(arg_name="connectionInfo", type="signalRConnectionInfo", hubName="serverless", connectionStringSetting="AzureSignalRConnectionString")
def negotiate(req: func.HttpRequest, connectionInfo) -> func.HttpResponse:
return func.HttpResponse(connectionInfo)
此函式可讓用戶端取得存取令牌。
建立廣播函式。
新增下列程式代碼以新增 函 broadcast
式
@app.timer_trigger(schedule="*/1 * * * *", arg_name="myTimer",
run_on_startup=False,
use_monitor=False)
@app.generic_output_binding(arg_name="signalRMessages", type="signalR", hubName="serverless", connectionStringSetting="AzureSignalRConnectionString")
def broadcast(myTimer: func.TimerRequest, signalRMessages: func.Out[str]) -> None:
global etag
global start_count
headers = {'User-Agent': 'serverless', 'If-None-Match': etag}
res = requests.get('https://api.github.com/repos/azure/azure-functions-python-worker', headers=headers)
if res.headers.get('ETag'):
etag = res.headers.get('ETag')
if res.status_code == 200:
jres = res.json()
start_count = jres['stargazers_count']
signalRMessages.set(json.dumps({
'target': 'newMessage',
'arguments': [ 'Current star count of https://api.github.com/repos/azure/azure-functions-python-worker is: ' + str(start_count) ]
}))
此函式會使用時間觸發程式定期將訊息廣播到所有用戶端。
建立 Azure Function 專案
建立本機 Azure Function 專案。
- 從命令列為專案建立目錄。
- 變更為專案目錄。
- 使用 Azure Functions
func init
命令來初始化函式專案。
# Initialize a function project
func init --worker-runtime python --model v1
建立函式
初始化專案之後,您必須建立函式。 此專案需要三個函式:
index
:裝載用戶端的網頁。negotiate
:允許用戶端取得存取權杖。broadcast
:使用時間觸發程序定期將訊息廣播到所有用戶端。
當您從專案的根目錄執行 func new
命令時,Azure Functions Core Tools 會建立預設函式來源檔案,並將其儲存在以 函式命名的資料夾中。 您將視需要編輯檔案,並以應用程式程式碼取代預設程式碼。
建立索引函式
您可使用此範例函式作為您自己函式的範本。
- 執行下列命令建立
index
函式。
func new -n index -t HttpTrigger
- 編輯 index/function.json,並以下列 json 程式碼取代內容:
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
- 編輯 index/_init_.py,並以下列程式碼取代內容:
import os
import azure.functions as func
def main(req: func.HttpRequest) -> func.HttpResponse:
f = open(os.path.dirname(os.path.realpath(__file__)) + '/../content/index.html')
return func.HttpResponse(f.read(), mimetype='text/html')
建立交涉函式
- 執行下列命令以建立
negotiate
函式。
func new -n negotiate -t HttpTrigger
- 編輯 negotiate/function.json,並以下列 json 程式碼取代內容:
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
},
{
"type": "signalRConnectionInfo",
"name": "connectionInfo",
"hubName": "serverless",
"connectionStringSetting": "AzureSignalRConnectionString",
"direction": "in"
}
]
}
- 編輯 negotiate/_init_.py,並以下列程式碼取代內容:
import azure.functions as func
def main(req: func.HttpRequest, connectionInfo) -> func.HttpResponse:
return func.HttpResponse(connectionInfo)
建立廣播函式。
- 執行下列命令以建立
broadcast
函式。
func new -n broadcast -t TimerTrigger
# install requests
pip install requests
- 編輯 broadcast/function.json,並以下列程式碼取代內容:
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "myTimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "*/5 * * * * *"
},
{
"type": "signalR",
"name": "signalRMessages",
"hubName": "serverless",
"connectionStringSetting": "AzureSignalRConnectionString",
"direction": "out"
}
]
}
- 編輯 broadcast/_init_.py,並以下列程式碼取代內容:
import requests
import json
import azure.functions as func
etag = ''
start_count = 0
def main(myTimer: func.TimerRequest, signalRMessages: func.Out[str]) -> None:
global etag
global start_count
headers = {'User-Agent': 'serverless', 'If-None-Match': etag}
res = requests.get('https://api.github.com/repos/azure/azure-signalr', headers=headers)
if res.headers.get('ETag'):
etag = res.headers.get('ETag')
if res.status_code == 200:
jres = res.json()
start_count = jres['stargazers_count']
signalRMessages.set(json.dumps({
'target': 'newMessage',
'arguments': [ 'Current star count of https://github.com/Azure/azure-signalr is: ' + str(start_count) ]
}))
建立 index.html 檔案
此應用程式的用戶端介面是網頁。 index
函式會從 content/index.html 檔案讀取 HTML 內容。
- 在專案根資料夾中建立名為
content
的資料夾。 - 建立檔案 content/index.html。
- 將下列內容複製到 content/index.html 檔案並加以儲存:
<html>
<body>
<h1>Azure SignalR Serverless Sample</h1>
<div id="messages"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.min.js"></script>
<script>
let messages = document.querySelector('#messages');
const apiBaseUrl = window.location.origin;
const connection = new signalR.HubConnectionBuilder()
.withUrl(apiBaseUrl + '/api')
.configureLogging(signalR.LogLevel.Information)
.build();
connection.on('newMessage', (message) => {
document.getElementById("messages").innerHTML = message;
});
connection.start()
.catch(console.error);
</script>
</body>
</html>
將 SignalR Service 連接字串新增至函式應用程式設定
最後一個步驟是在 Azure Function 應用程式設定中設定 SignalR Service 連接字串。
在 Azure 入口網站中,移至您稍早部署的 SignalR 執行個體。
選取 [金鑰] 以檢視 SignalR 服務執行個體的連接字串。
複製主要連接字串,然後執行命令:
func settings add AzureSignalRConnectionString "<signalr-connection-string>"
在本機執行 Azure Function 應用程式
啟動 Azurite 儲存體模擬器:
azurite
在本機環境中執行 Azure Function 應用程式:
func start
注意
如果您在 Blob 儲存體上看到顯示讀取錯誤的錯誤,請確定 local.settings.json 檔案中的 'AzureWebJobsStorage' 設定設為 UseDevelopmentStorage=true
。
在本機執行 Azure Function 之後,請移至 http://localhost:7071/api/index
。 此頁面會顯示 GitHub Azure/azure-signalr 存放庫的目前星號計數。 當您在 GitHub 中將存放庫加上星號或取消星號時,每隔幾秒鐘就會看到重新整理的計數。
清除資源
如果您將不繼續使用此應用程式,請使用下列步驟來刪除本快速入門所建立的全部資源,這樣才不會產生任何費用:
在 Azure 入口網站中選取最左側的 [資源群組],然後選取您所建立的資源群組。 或者,您也可以使用搜尋方塊來依資源群組的名稱尋找它。
在開啟的視窗中選取資源群組,然後按一下 [刪除資源群組]。
在新視窗中輸入要刪除之資源群組的名稱,然後按一下 [刪除]。
下一步
在此快速入門中,您已在本機建置並執行即時無伺服器應用程式。 接下來,深入了解如何透過 SignalR Service 使用用戶端與 Azure Function 之間的雙向通訊。