共用方式為


使用命令列工具將 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 儲存體帳戶。 此帳戶的連接字串會安全地儲存在 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: