練習 - 將邏輯新增至函數應用程式
讓我們繼續進行齒輪驅動範例,並新增溫度服務的邏輯。 具體而言,我們將從 HTTP 要求接收資料。
函式需求
首先,我們需要為邏輯定義一些需求:
- 從 0 到 25 度的溫度應該標示為正常。
- 從 25 到 50 度的溫度應該標示為警告。
- 超過 50 度的溫度應該標示為危險。
將函式新增至函數應用程式
如上一個單元中所討論,Azure 會提供可協助您建置函式的範本。 在此單元中,您將使用 HttpTrigger
範本來實作溫度服務。
在上一個練習中,您已部署函式應用程式並加以開啟。 如果尚未開啟,您可以從首頁選取 [所有資源],然後選取您的函式應用程式,其具有如 escalator-functions-xxx 的名稱。
在 [函數] 索引標籤底下的 [函數應用程式] 畫面上,選取 [在 Azure 入口網站中建立]。 [建立函式] 窗格隨即出現。
在 [選取範本] 底下,選取 [HTTP 觸發程序],然後選取 [下一頁]。
讓 [函數名稱] 保留為「HttpTrigger1」,讓 [授權等級] 保留為 [函數],然後選取 [建立]。 函數 HttpTrigger1 隨即建立,並顯示在 [HttpTrigger1 函數] 窗格中。
選取 [編碼 + 測試] 索引標籤。程式碼編輯器隨即開啟,顯示函式的 index.js 程式碼檔案內容。 HTTP 範本所產生的預設程式碼隨即出現在下列程式碼片段中。
module.exports = async function (context, req) { context.log('JavaScript HTTP trigger function processed a request.'); const name = (req.query.name || (req.body && req.body.name)); const responseMessage = name ? "Hello, " + name + ". This HTTP triggered function executed successfully." : "This HTTP triggered function executed successfully. Pass a name on the query string or in the request body for a personalized response."; context.res = { // status: 200, /* Defaults to 200 */ body: responseMessage }; }
您的函式預期會透過 HTTP 要求查詢字串傳遞名稱,或作為要求主體的一部分來傳遞。 函式的回應是傳回訊息「<name>,您好。此 HTTP 觸發程序函數已成功執行。」,以回應要求所傳送的名稱。
從 [來源檔案] 下拉式清單中,選取 function.json 來檢視函式的設定,其看起來應該會像下列程式碼。
{ "bindings": [ { "authLevel": "function", "type": "httpTrigger", "direction": "in", "name": "req", "methods": [ "get", "post" ] }, { "type": "http", "direction": "out", "name": "res" } ] }
此設定檔宣告函數會在收到 HTTP 要求時執行。 輸出繫結宣告回應會以 HTTP 回應的形式傳送。
在 [範本詳細資料] 區段的 [新增函式] 欄位中,輸入 DriveGearTemperatureService。 將 [授權等級] 保留為函式,然後選取 [建立] 來建立函式。 DriveGearTemperatureService 函式的 [概觀] 窗格隨即出現。
在 [函式] 功能表中,選取 [程式碼 + 測試]。 程式碼編輯器會開啟並顯示 run.ps1 程式碼檔案的內容。 下列程式碼片段會列出範本為我們產生的預設程式碼。
using namespace System.Net # Input bindings are passed in via param block. param($Request, $TriggerMetadata) # Write to the Azure Functions log stream. Write-Host "PowerShell HTTP trigger function processed a request." # Interact with query parameters or the body of the request. $name = $Request.Query.Name if (-not $name) { $name = $Request.Body.Name } $body = "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." if ($name) { $body = "Hello, $name. This HTTP triggered function executed successfully." } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body })
我們的函式預期會透過 HTTP 要求查詢字串傳遞名稱,或作為要求主體的一部分來傳遞。 HTTP 函式必須透過寫入其輸出繫結來產生回應,這是使用
Push-OutputBinding
Cmdlet 在 PowerShell 函式中完成的。 此函式會傳回訊息「$name,您好」,以回應在要求中傳送的名稱。從來源下拉式清單中,選取 [function.json] 來檢視函式的設定,畫面應該如下所示。
{ "bindings": [ { "authLevel": "function", "type": "httpTrigger", "direction": "in", "name": "Request", "methods": [ "get", "post" ] }, { "type": "http", "direction": "out", "name": "Response" } ] }
此設定會宣告當它收到 HTTP 要求時,函式已執行。 輸出繫結宣告回應會以 HTTP 回應的形式傳送。
測試函式
提示
cURL 是一種命令列工具,可用來傳送或接收檔案。 cURL 隨附於 Linux、macOS 和 Windows 10,絕大多數其他作業系統都可以下載。 cURL 支援多種通訊協定,如 HTTP、HTTPS、FTP、FTPS、SFTP、LDAP、TELNET、SMTP、POP3 等等。 如需詳細資訊,請前往下面連結:
若要測試函數,您可以在命令列上使用 cURL,將 HTTP 要求傳送至函數 URL。
展開 [觸發程序函式] 窗格底部的 [記錄] 框架。 在 [記錄] 框架頂端的下拉式清單中選取 [Filesystem Logs] (檔案系統記錄檔)。 記錄框架應每分鐘開始累積追蹤通知。
若要尋找函式的端點 URL,請從命令列選取 [取得函式 URL],如下圖所示。 選取 URL 結尾處的 [複製到剪貼簿] 圖示,以儲存此連結。 將此連結儲存至記事本或類似的應用程式,以供稍後使用。
開啟命令提示字元,然後執行 cURL 將 HTTP 要求傳送至函式 URL。 請務必使用您在先前步驟中複製的 URL。
curl "<your-https-url>"
提示
您可能需要將 URL 包覆在引號中,以避免 URL 中出現特殊字元的問題。
如果您使用 Windows,請從命令提示字元執行cURL
。 PowerShell 有一個 curl 命令,但其為 Invoke-WebRequest 的別名,與cURL
不同。回應應該會顯示如下。
This HTTP triggered function executed successfully. Pass a name on the query string or in the request body for a personalized response.
現在,請在要求中傳入名稱。 為此,您必須將名為
name
的查詢字串參數新增至 URL。 下列範例會新增查詢字串參數name=Azure
。curl "<your-https-url>&name=Azure"
回應應該會顯示如下。
Hello, Azure. This HTTP triggered function executed successfully.
函式已成功執行,並傳回您在要求中傳入的名稱。
保護 HTTP 觸發程序
HTTP 觸發程序可讓您使用 API 金鑰封鎖未知的呼叫端,但需要金鑰作為要求的一部分。 當您建立函式時,您要選取 [授權層級]。 依預設,等級會設定為 [函數],因而需要函數專用的 API 金鑰。 此外也可設定為「管理員」以使用全域主要金鑰,或設為「匿名」以指出不需要金鑰。 您也可以在建立後透過函式的屬性變更授權層級。
因為您在建立此函式時指定了「函數」,所以,當您傳送 HTTP 要求時需要提供金鑰。 您可以將它傳送為名為 code
的查詢字串參數。 或者,使用慣用的方法,並將它當作名為 x-functions-key
的 HTTP 標頭傳遞。
若要尋找函數金鑰,請在 [概觀] 功能表上的 [函數] 索引標籤下選取函數的名稱 (例如「HttpTriger1」),以開啟 [編碼 + 測試] 功能表。 然後,選取 [函數金鑰] 索引標籤。
根據預設,函式金鑰值是隱藏的。 選取 [顯示值] 以顯示預設函數金鑰值。 將 [值] 欄位的內容複寫到剪貼簿,然後將此金鑰儲存在 [記事本] 或類似的應用程式以供稍後使用。
若要使用函式金鑰測試函式,請開啟命令提示字元並執行 cURL,以將 HTTP 要求傳送至函式 URL。 將
<your-function-key>
取代為您儲存的函數金鑰值,並將<your-https-url>
取代為您函數的 URL。curl --header "Content-Type: application/json" --header "x-functions-key: <your-function-key>" --request POST --data "{\"name\": \"Azure Function\"}" <your-https-url>
檢閱 cURL 命令,並確認其具有下列值:
- 已新增類型為
application/json
的Content-Type
標頭值。 - 已將函式金鑰當成標頭值
x-functions-key
來傳遞。 - 已使用
POST
要求。 - 使用函式的 URL 傳遞 Azure 函式。
- 已新增類型為
檢查記錄。
[程式碼 + 測試] 窗格應該會開啟顯示記錄檔輸出的工作階段 (確定已在 [記錄] 窗格頂端的下拉式清單中選取 [Filesystem Logs] (檔案系統記錄檔))。 記錄檔會以您的要求狀態進行更新,應該會顯示如下:
```output
2022-02-16T22:34:10.473 [Information] Executing 'Functions.HttpTrigger1' (Reason='This function was programmatically called via the host APIs.', Id=4f503b35-b944-455e-ba02-5205f9e8b47a)
2022-02-16T22:34:10.539 [Information] JavaScript HTTP trigger function processed a request.
2022-02-16T22:34:10.562 [Information] Executed 'Functions.HttpTrigger1' (Succeeded, Id=4f503b35-b944-455e-ba02-5205f9e8b47a, Duration=114ms)
```
```output
2022-02-16T21:07:11.340 [Information] INFORMATION: PowerShell HTTP trigger function processed a request.
2022-02-16T21:07:11.449 [Information] Executed 'Functions.DriveGearTemperatureService' (Succeeded, Id=25e2edc3-542f-4629-a152-cf9ed99680d8, Duration=1164ms)
```
將商務邏輯新增至函數
讓我們將邏輯新增至函式,檢查所收到的溫度讀數,並設定每個溫度讀數的狀態。
我們的函式預期溫度讀數陣列。 下列 JSON 程式碼片段是我們會傳送至函數的要求本文範例。 JavaScript 或 PowerShell 的陣列名稱可能會略微不同,但陣列中的每個項目都有識別碼、時間戳記和溫度。
{
"Readings": [
{
"driveGearId": 1,
"timestamp": 1534263995,
"temperature": 23
},
{
"driveGearId": 3,
"timestamp": 1534264048,
"temperature": 45
},
{
"driveGearId": 18,
"timestamp": 1534264050,
"temperature": 55
}
]
}
讓我們以下列會實作商務邏輯的程式碼來取代函數中的預設程式碼。
在 HttpTrigger1 函式窗格中,開啟 index.js 檔案,並將其取代為下列程式碼。 在完成變更後,從命令列選取 [儲存],將更新儲存至檔案。
module.exports = function (context, req) {
context.log('Drive Gear Temperature Service triggered');
if (req.body && req.body.readings) {
req.body.readings.forEach(function(reading) {
if(reading.temperature<=25) {
reading.status = 'OK';
} else if (reading.temperature<=50) {
reading.status = 'CAUTION';
} else {
reading.status = 'DANGER'
}
context.log('Reading is ' + reading.status);
});
context.res = {
// status: 200, /* Defaults to 200 */
body: {
"readings": req.body.readings
}
};
}
else {
context.res = {
status: 400,
body: "Please send an array of readings in the request body"
};
}
context.done();
};
我們新增的邏輯很簡單。 我們會逐一查看陣列,並根據溫度欄位的值,將狀態設定為正常、警告或危險。 然後傳回已將狀態欄位新增至每個項目的讀數陣列。
當您展開窗格底部的 [記錄] 時,請注意 Log
陳述式。 當函式執行時,這些陳述式會在 [記錄] 視窗中新增訊息。
測試商務邏輯
我們將會使用 [開發人員]>[程式碼 + 測試] 中的 [測試/執行] 功能來測試函式。
在 [編碼 + 測試] 索引標籤上,選取 [測試/執行]。 在 [輸入] 索引標籤中,以下列程式碼取代 [本文] 文字輸入框的內容,以便建立我們的範例要求。
{ "readings": [ { "driveGearId": 1, "timestamp": 1534263995, "temperature": 23 }, { "driveGearId": 3, "timestamp": 1534264048, "temperature": 45 }, { "driveGearId": 18, "timestamp": 1534264050, "temperature": 55 } ] }
開啟 run.ps1 檔案,並以下列程式碼取代內容。 在完成變更後,從命令列選取 [儲存],將更新儲存至檔案。
using namespace System.Net
param($Request, $TriggerMetadata)
Write-Host "Drive Gear Temperature Service triggered"
$readings = $Request.Body.Readings
if ($readings) {
foreach ($reading in $readings) {
if ($reading.temperature -le 25) {
$reading.Status = "OK"
}
elseif ($reading.temperature -le 50) {
$reading.Status = "CAUTION"
}
else {
$reading.Status = "DANGER"
}
Write-Host "Reading is $($reading.Status)"
}
$status = [HttpStatusCode]::OK
$body = $readings
}
else {
$status = [HttpStatusCode]::BadRequest
$body = "Please send an array of readings in the request body"
}
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = $status
Body = $body
})
我們新增的邏輯很簡單。 我們會逐一查看陣列,並根據溫度欄位的值,將狀態設定為正常、警告或危險。 然後傳回已將狀態欄位新增至每個項目的讀數陣列。
請注意對 Write-Host
Cmdlet 的呼叫。 當函式執行時,這些陳述式會在 [記錄] 視窗中新增訊息。
測試商務邏輯
我們將會使用 [開發人員]>[程式碼 + 測試] 中的 [測試/執行] 功能來測試函式。
在 [編碼 + 測試] 索引標籤上,選取 [測試/執行]。 在 [輸入] 索引標籤中,以下列程式碼取代 [本文] 文字輸入框的內容,以便建立我們的範例要求。
{ "Readings": [ { "driveGearId": 1, "timestamp": 1534263995, "temperature": 23 }, { "driveGearId": 3, "timestamp": 1534264048, "temperature": 45 }, { "driveGearId": 18, "timestamp": 1534264050, "temperature": 55 } ] }
選取執行。 [輸出] 索引標籤會顯示 HTTP 回應碼和內容。 若要查看記錄訊息,請在窗格底部的飛出視窗中開啟 [記錄] 索引標籤 (如果尚未開啟)。 下圖顯示在輸出窗格中的範例回應,以及 [記錄] 窗格中的訊息。
[輸出] 索引標籤中可看到每個讀數均已正確新增狀態欄位。
在左側的 [開發人員] 功能表中,選取 [監視] 即可看到要求已記錄至 Application Insights。 您函式的 [監視器] 窗格隨即出現。
窗格的 [引動過程] 索引標籤會顯示每個函數引動過程的 [引動過程追蹤]。 選取其中一個引動過程的 [資料 (UTC)] 值,並檢視關於函數執行的詳細資料。