使用命令列工具將 Azure Functions 連線到 Azure 儲存體
在本文中,您將整合 Azure 儲存體佇列與您在上一篇快速入門文章中建立的函式和儲存體帳戶。 您可以使用輸出繫結將 HTTP 要求中的資料寫入至佇列中的訊息,以完成這項整合。 完成本文的作業,並不會在先前的快速入門收取的幾美分以外產生額外的費用。 若要深入了解繫結,請參閱 Azure Functions 觸發程序和繫結概念。
設定您的本機環境
開始之前,您必須完成快速入門:從命令列建立 Azure Functions 專案本文中的指示。 如果您已在該文章結束時清除資源,請重新執行這些步驟以在 Azure 中重新建立函式應用程式和相關資源。
開始之前,您必須完成快速入門:從命令列建立 Azure Functions 專案本文中的指示。 如果您已在該文章結束時清除資源,請重新執行這些步驟以在 Azure 中重新建立函式應用程式和相關資源。
開始之前,您必須完成快速入門:從命令列建立 Azure Functions 專案本文中的指示。 如果您已在該文章結束時清除資源,請重新執行這些步驟以在 Azure 中重新建立函式應用程式和相關資源。
開始之前,您必須完成快速入門:從命令列建立 Azure Functions 專案本文中的指示。 如果您已在該文章結束時清除資源,請重新執行這些步驟以在 Azure 中重新建立函式應用程式和相關資源。
開始之前,您必須完成快速入門:從命令列建立 Azure Functions 專案本文中的指示。 如果您已在該文章結束時清除資源,請重新執行這些步驟以在 Azure 中重新建立函式應用程式和相關資源。
開始之前,您必須完成快速入門:從命令列建立 Azure Functions 專案本文中的指示。 如果您已在該文章結束時清除資源,請重新執行這些步驟以在 Azure 中重新建立函式應用程式和相關資源。
擷取 Azure 儲存體連接字串
您稍早已建立可供函式應用程式使用的 Azure 儲存體帳戶。 此帳戶的連接字串會安全地儲存在 Azure 的應用程式設定中。 藉由將設定下載到 local.settings.json 檔案中,您可以在本機執行函式時,使用該連線寫入至相同帳戶中的儲存體佇列。
從專案的根目錄執行下列命令 (請將
<APP_NAME>
取代為先前步驟中的函式應用程式名稱)。 此命令會覆寫檔案中任何現有的值。func azure functionapp fetch-app-settings <APP_NAME>
開啟 local.settings.json 檔案並找出名為
AzureWebJobsStorage
的值,也就是儲存體帳戶連接字串。 您會在本文的其他章節中使用名稱AzureWebJobsStorage
和連接字串。
重要
由於 local.settings.json 檔案中包含從 Azure 下載的祕密,因此請一律將此檔案排除在原始檔控制以外。 使用本機函式專案建立的 .gitignore 檔案依預設會排除該檔案。
註冊繫結延伸模組
除了 HTTP 和計時器觸發程序以外,繫結皆會以擴充套件的形式實作。 在終端機視窗中執行下列 dotnet add package 命令來將儲存體套件新增至您的專案。
dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues --prerelease
現在,您可以將儲存體輸出繫結新增至您的專案。
將輸出繫結定義新增至函式
一個函式只能有一個觸發程序,但可以有多個輸入和輸出繫結,如此,您無須撰寫自訂整合程式碼,即可連線至其他 Azure 服務和資源。
使用 Node.js v4 程式設計模型時,系結屬性會直接定義在 ./src/functions/HttpExample.js 檔案中。 從上一個快速入門中,您的檔案已經包含 方法所 app.http
定義的 HTTP 系結。
const { app } = require('@azure/functions');
app.http('httpTrigger', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: async (request, context) => {
try {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text());
context.log(`Name: ${name}`);
if (!name) {
return { status: 404, body: 'Not Found' };
}
return { body: `Hello, ${name}!` };
} catch (error) {
context.log(`Error: ${error}`);
return { status: 500, body: 'Internal Server Error' };
}
},
});
使用 Node.js v4 程式設計模型時,系結屬性會直接定義在 ./src/functions/HttpExample.js 檔案中。 從上一個快速入門中,您的檔案已經包含 方法所 app.http
定義的 HTTP 系結。
import {
app,
HttpRequest,
HttpResponseInit,
InvocationContext,
} from '@azure/functions';
export async function httpTrigger1(
request: HttpRequest,
context: InvocationContext,
): Promise<HttpResponseInit> {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text()) || 'world';
return { body: `Hello, ${name}!` };
}
app.http('httpTrigger1', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: httpTrigger1,
});
您會在函式資料夾中的 function.json 檔案中宣告這些繫結。 在先前的快速入門中,HttpExample 資料夾中的 function.json 檔案包含 bindings
集合中的兩個繫結:
使用 Python v2 程式設計模型時,系結屬性會直接在function_app.py檔案中定義為裝飾專案。 在上一個快速入門中,function_app.py 檔案已包含一個裝飾項目型繫結:
import azure.functions as func
import logging
app = func.FunctionApp()
@app.function_name(name="HttpTrigger1")
@app.route(route="hello", auth_level=func.AuthLevel.ANONYMOUS)
route
裝飾項目會將 HttpTrigger 和 HttpOutput 繫結新增至函式,這可讓您的函式在 HTTP 要求達到指定路由時觸發。
若要從此函式寫入 Azure 儲存體佇列,請將 queue_output
裝飾項目新增至函式程式碼:
@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")
在裝飾項目中,arg_name
會識別程式碼中參考的繫結參數、queue_name
是寫入繫結的佇列名稱,而 connection
是包含儲存體帳戶連接字串的應用程式設定名稱。 在快速入門中,您會使用與函數應用程式相同的儲存體帳戶 (使用 local.settings.json 檔案中的 AzureWebJobsStorage
設定)。 當 queue_name
不存在,繫結會在第一次使用時加以建立。
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
若要寫入至 Azure 儲存體佇列:
將
extraOutputs
屬性新增至繫結組態{ methods: ['GET', 'POST'], extraOutputs: [sendToQueue], // add output binding to HTTP trigger authLevel: 'anonymous', handler: () => {} }
在
app.http
呼叫上方新增output.storageQueue
函式const sendToQueue: StorageQueueOutput = output.storageQueue({ queueName: 'outqueue', connection: 'AzureWebJobsStorage', });
集合中的第二個繫結名為 res
。 此 http
繫結是用來寫入 HTTP 回應的輸出繫結 (out
)。
若要從這個函式寫入至 Azure 儲存體佇列,請新增類型為 queue
、名稱為 msg
的 out
繫結,如下列程式碼所示:
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
},
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outqueue",
"connection": "AzureWebJobsStorage"
}
]
}
queue
針對類型,您必須在 中queueName
指定佇列的名稱,並在 中connection
提供 Azure 儲存體 連接的名稱(從 local.settings.json 檔案)。
在 C# 專案中,是將繫結定義為函式方法上的繫結屬性。 確切的定義取決於您的應用程式是否在程序中執行 (C# 類別庫),還是處於隔離的背景工作處理序中。
開啟 HttpExample.cs 專案檔,並新增下列 MultiResponse
類別:
public class MultiResponse
{
[QueueOutput("outqueue",Connection = "AzureWebJobsStorage")]
public string[] Messages { get; set; }
public HttpResponseData HttpResponse { get; set; }
}
MultiResponse
類別可讓您寫入名為 outqueue
的儲存體佇列和 HTTP 成功訊息。 多個訊息可以傳送至佇列,因為 QueueOutput
屬性會套用至字串陣列。
Connection
屬性會設定儲存體帳戶的連接字串。 在此情況下,您可以省略 Connection
,因為您已經正在使用預設的儲存體帳戶。
在 Java 專案中,繫結會被定義為函式方法上的繫結註釋。 系統接著會根據這些註釋自動產生 function.json 檔案。
瀏覽至 src/main/java 底下您的函式程式碼位置,開啟 Function java 專案檔案,然後將下列參數新增至 run
方法定義:
@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") OutputBinding<String> msg
msg
參數是 OutputBinding<T>
類型,表示字串的集合。 這些字串以訊息方式寫入,以在函數完成時輸出繫結。 在此情況下,輸出是名為 outqueue
的儲存體佇列。 儲存體帳戶的連接字串是由 connection
方法設定。 您會傳遞包含儲存體帳戶連接字串的應用程式設定,而非連接字串本身。
run
方法定義現在必須如下列範例所示︰
@FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage")
OutputBinding<String> msg, final ExecutionContext context) {
...
}
如需繫結的詳細資訊,請參閱 Azure Functions 觸發程序和繫結概念與佇列輸出設定。
新增程式碼以使用輸出繫結
定義了佇列繫結後,您現在可以更新函式以接收 msg
輸出參數,並將訊息寫入至佇列。
將 msg
參數新增至函式定義和 if name:
陳述式下的 msg.set(name)
,以更新 HttpExample\function_app.py,使其符合下列程式碼:
import azure.functions as func
import logging
app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)
@app.route(route="HttpExample")
@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")
def HttpExample(req: func.HttpRequest, msg: func.Out [func.QueueMessage]) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
name = req.params.get('name')
if not name:
try:
req_body = req.get_json()
except ValueError:
pass
else:
name = req_body.get('name')
if name:
msg.set(name)
return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
else:
return func.HttpResponse(
"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
status_code=200
)
msg
參數是 azure.functions.Out class
的執行個體。 set
方法會將字串訊息寫入至佇列。 在此案例中,即為傳送至 URL 查詢字串中函式的 name
。
新增會使用 context.extraOutputs
上的輸出繫結物件的程式碼來建立佇列訊息。 在 return 陳述式之前新增此程式碼。
context.extraOutputs.set(sendToQueue, [msg]);
此時,函式看起來會如下所示:
const { app, output } = require('@azure/functions');
const sendToQueue = output.storageQueue({
queueName: 'outqueue',
connection: 'AzureWebJobsStorage',
});
app.http('HttpExample', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
extraOutputs: [sendToQueue],
handler: async (request, context) => {
try {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text());
context.log(`Name: ${name}`);
if (name) {
const msg = `Name passed to the function ${name}`;
context.extraOutputs.set(sendToQueue, [msg]);
return { body: msg };
} else {
context.log('Missing required data');
return { status: 404, body: 'Missing required data' };
}
} catch (error) {
context.log(`Error: ${error}`);
return { status: 500, body: 'Internal Server Error' };
}
},
});
新增會使用 context.extraOutputs
上的輸出繫結物件的程式碼來建立佇列訊息。 在 return 陳述式之前新增此程式碼。
context.extraOutputs.set(sendToQueue, [msg]);
此時,函式看起來會如下所示:
import {
app,
output,
HttpRequest,
HttpResponseInit,
InvocationContext,
StorageQueueOutput,
} from '@azure/functions';
const sendToQueue: StorageQueueOutput = output.storageQueue({
queueName: 'outqueue',
connection: 'AzureWebJobsStorage',
});
export async function HttpExample(
request: HttpRequest,
context: InvocationContext,
): Promise<HttpResponseInit> {
try {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text());
context.log(`Name: ${name}`);
if (name) {
const msg = `Name passed to the function ${name}`;
context.extraOutputs.set(sendToQueue, [msg]);
return { body: msg };
} else {
context.log('Missing required data');
return { status: 404, body: 'Missing required data' };
}
} catch (error) {
context.log(`Error: ${error}`);
return { status: 500, body: 'Internal Server Error' };
}
}
app.http('HttpExample', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: HttpExample,
});
新增使用 Push-OutputBinding
Cmdlet 的程式碼,以使用 msg
輸出繫結將文字寫入至佇列。 在 if
陳述式中設定「確定」狀態之前,請先新增此程式碼。
$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg
此時,您的函式必須顯示如下:
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
}
if ($name) {
# Write the $name value to the queue,
# which is the name passed to the function.
$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg
$status = [HttpStatusCode]::OK
$body = "Hello $name"
}
else {
$status = [HttpStatusCode]::BadRequest
$body = "Please pass a name on the query string or in the request body."
}
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = $status
Body = $body
})
將現有的 HttpExample
類別取代為下列程式碼:
[Function("HttpExample")]
public static MultiResponse Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("HttpExample");
logger.LogInformation("C# HTTP trigger function processed a request.");
var message = "Welcome to Azure Functions!";
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString(message);
// Return a response to both HTTP trigger and storage output binding.
return new MultiResponse()
{
// Write a single message.
Messages = new string[] { message },
HttpResponse = response
};
}
}
現在,您可以使用新的 msg
參數,從您的函式程式碼寫入輸出繫結。 在成功回應之前新增下列一行程式碼,以將 name
的值新增至 msg
輸出繫結。
msg.setValue(name);
當您使用輸出繫結時,無須使用 Azure 儲存體 SDK 程式碼來進行驗證、取得佇列參考或寫入資料。 Functions 執行階段和佇列輸出繫結會為您進行這些工作。
您的 run
方法現在看起來必須如下列範例所示:
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(name = "msg", queueName = "outqueue",
connection = "AzureWebJobsStorage") OutputBinding<String> msg,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
String query = request.getQueryParameters().get("name");
String name = request.getBody().orElse(query);
if (name == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
.body("Please pass a name on the query string or in the request body").build();
} else {
// Write the name to the message queue.
msg.setValue(name);
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
}
更新測試
因為原型也會建立一組測試,所以您需要更新這些測試,以處理 run
方法簽章中的新 msg
參數。
瀏覽至 src/test/java 底下的測試程式碼位置,開啟 Function.java 專案檔,並以下列程式碼取代 //Invoke
下的程式碼行:
@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);
final HttpResponseMessage ret = new Function().run(req, msg, context);
請留意,您無須撰寫任何程式碼來進行驗證、取得佇列參考或寫入資料。 這些整合工作全都可在 Azure Functions 執行階段和佇列輸出繫結中輕易處理。
在本機執行函式
從 LocalFunctionProj 資料夾啟動本機 Azure Functions 執行階段主機以執行您的函式。
func start
在輸出的結尾處,必須出現下列幾行:
注意
如果 HttpExample 未如上顯示,表示您可能不是從專案的根資料夾啟動主機。 在此情況下,請使用 Ctrl+C 來停止主機並前往專案的根資料夾,然後再次執行先前的命令。
從此輸出中,將 HTTP 函數的 URL 複製到瀏覽器,並附加查詢字串
?name=<YOUR_NAME>
,以製作完整的 URL,如http://localhost:7071/api/HttpExample?name=Functions
。 瀏覽器應該會顯示回應訊息,以回應您的查詢字串值。 您在其中啟動專案的終端機,也會在您提出要求時顯示記錄輸出。當您完成時,請按 Ctrl+C,然後輸入
y
以停止函數主機。
提示
在啟動期間,主機會下載並安裝儲存體繫結延伸模組和其他 Microsoft 繫結延伸模組。 之所以會執行此安裝,是因為具有下列屬性的 host.json 檔案依預設會啟用繫結延伸模組:
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
如果發生任何與繫結延伸模組相關的錯誤,請檢查 host.json 中是否有上述屬性存在。
檢視 Azure 儲存體佇列中的訊息
您可以在 Azure 入口網站或 Microsoft Azure 儲存體總管中檢視佇列。 您也可以在 Azure CLI 中檢視佇列,如下列步驟所說明:
開啟函式專案的 local.setting.json 檔案,並複製連接字串值。 在終端機或命令視窗中,執行下列命令 (請貼上您的特定連接字串以取代
<MY_CONNECTION_STRING>
),以建立名為AZURE_STORAGE_CONNECTION_STRING
的環境變數。 (此環境變數意味著您無須使用--connection-string
引數將連接字串提供給每個後續命令。)export AZURE_STORAGE_CONNECTION_STRING="<MY_CONNECTION_STRING>"
(選用) 使用
az storage queue list
命令檢視您帳戶中的儲存體佇列。 此命令的輸出必須包含名為outqueue
的佇列,這是函式將其第一個訊息寫入至該佇列時所建立的。az storage queue list --output tsv
使用
az storage message get
命令來讀取此佇列中的訊息,這應該是您先前測試函式時所提供的值。 此命令會讀取並移除佇列中的第一個訊息。echo `echo $(az storage message get --queue-name outqueue -o tsv --query '[].{Message:content}') | base64 --decode`
由於訊息本文會以 base64 編碼儲存,因此必須先將訊息解碼才會顯示。 執行
az storage message get
之後,就會從佇列中移除此訊息。 如果outqueue
中只有一個訊息,則當您第二次執行此命令時,將不會擷取訊息,而是會收到錯誤。
將專案重新部署至 Azure
現在,您已在本機確認函式已將訊息寫入至 Azure 儲存體佇列,您可以重新部署專案,以更新在 Azure 上執行的端點。
在 LocalFunctionsProj 資料夾中,使用 func azure functionapp publish
命令來重新部署專案 (請將 <APP_NAME>
取代為您的應用程式名稱)。
func azure functionapp publish <APP_NAME>
在 [本機專案] 資料夾中,使用下列 Maven 命令來重新發佈專案:
mvn azure-functions:deploy
在 Azure 中驗證
如先前的快速入門所示,使用瀏覽器或 CURL 來測試已重新部署的函式。
再次檢查儲存體佇列 (如上一節所述),以確認其中包含寫入至佇列的新訊息。
清除資源
完成之後,請使用下列命令刪除資源群組及其包含的所有資源,以避免產生額外的成本。
az group delete --name AzureFunctionsQuickstart-rg
下一步
您已更新 HTTP 觸發的函式,以將資料寫入至儲存體佇列。 您現在可以深入了解如何使用 Core Tools 和 Azure CLI,從命令列開發 Functions: