使用命令列工具將 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 檔案中,您可以在本機執行函式時,使用該連線寫入至相同帳戶中的儲存體佇列。

  1. 從專案的根目錄執行下列命令 (請將 <APP_NAME> 取代為先前步驟中的函式應用程式名稱)。 此命令會覆寫檔案中任何現有的值。

    func azure functionapp fetch-app-settings <APP_NAME>
    
  2. 開啟 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、名稱為 msgout 繫結,如下列程式碼所示:

    {
      "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 執行階段和佇列輸出繫結中輕易處理。

在本機執行函式

  1. LocalFunctionProj 資料夾啟動本機 Azure Functions 執行階段主機以執行您的函式。

    func start
    

    在輸出的結尾處,必須出現下列幾行:

    在本機執行函式時終端機窗口輸出的螢幕快照。

    注意

    如果 HttpExample 未如上顯示,表示您可能不是從專案的根資料夾啟動主機。 在此情況下,請使用 Ctrl+C 來停止主機並前往專案的根資料夾,然後再次執行先前的命令。

  2. 從此輸出中,將 HTTP 函數的 URL 複製到瀏覽器,並附加查詢字串 ?name=<YOUR_NAME>,以製作完整的 URL,如 http://localhost:7071/api/HttpExample?name=Functions。 瀏覽器應該會顯示回應訊息,以回應您的查詢字串值。 您在其中啟動專案的終端機,也會在您提出要求時顯示記錄輸出。

  3. 當您完成時,請按 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 中檢視佇列,如下列步驟所說明:

  1. 開啟函式專案的 local.setting.json 檔案,並複製連接字串值。 在終端機或命令視窗中,執行下列命令 (請貼上您的特定連接字串以取代 <MY_CONNECTION_STRING>),以建立名為 AZURE_STORAGE_CONNECTION_STRING的環境變數。 (此環境變數意味著您無須使用 --connection-string 引數將連接字串提供給每個後續命令。)

    export AZURE_STORAGE_CONNECTION_STRING="<MY_CONNECTION_STRING>"
    
  2. (選用) 使用 az storage queue list 命令檢視您帳戶中的儲存體佇列。 此命令的輸出必須包含名為 outqueue 的佇列,這是函式將其第一個訊息寫入至該佇列時所建立的。

    az storage queue list --output tsv
    
  3. 使用 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 中驗證

  1. 如先前的快速入門所示,使用瀏覽器或 CURL 來測試已重新部署的函式。

    將發佈命令的輸出中顯示的完整叫用 URL 複製到瀏覽器網址列中 (請附加查詢參數 &name=Functions)。 瀏覽器應該會顯示與您在本機執行函式時的輸出相同。

  2. 再次檢查儲存體佇列 (如上一節所述),以確認其中包含寫入至佇列的新訊息。

清除資源

完成之後,請使用下列命令刪除資源群組及其包含的所有資源,以避免產生額外的成本。

az group delete --name AzureFunctionsQuickstart-rg

下一步

您已更新 HTTP 觸發的函式,以將資料寫入至儲存體佇列。 您現在可以深入了解如何使用 Core Tools 和 Azure CLI,從命令列開發 Functions: