适用于 Azure Functions 的 Azure 队列存储输出绑定

Azure Functions 可以通过设置输出绑定来创建新的 Azure 队列存储消息。

有关设置和配置详细信息,请参阅概述

重要

本文使用选项卡来支持多个版本的 Node.js 编程模型。 v4 模型目前处于预览状态,旨在为 JavaScript 和 TypeScript 开发人员提供更为灵活和直观的体验。 在升级指南中详细了解 v3 和 v4 之间的差异。

Azure Functions 支持两种 Python 编程模型。 定义绑定的方式取决于选择的编程模型。

使用 Python v2 编程模型,可以直接在 Python 函数代码中使用修饰器定义绑定。 有关详细信息,请参阅 Python 开发人员指南

本文同时支持两个编程模型。

示例

可以使用以下 C# 模式之一创建 C# 函数:

  • 进程内类库:编译的 C# 函数,该函数在与 Functions 运行时相同的进程中运行。
  • 独立进程类库:编译的 C# 函数,该函数在独立于运行时的进程中运行。 支持在 .NET 5.0 上运行的 C# 函数需要独立的进程。
  • C# 脚本:主要在 Azure 门户中创建 C# 函数时使用。
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using Azure.Storage.Queues.Models;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace SampleApp
{
    public class QueueFunction
    {
        private readonly ILogger<QueueFunction> _logger;

        public QueueFunction(ILogger<QueueFunction> logger)
        {
            _logger = logger;
        }

        //<docsnippet_queue_output_binding>
        //<docsnippet_queue_trigger>
        [Function(nameof(QueueFunction))]
        [QueueOutput("output-queue")]
        public string[] Run([QueueTrigger("input-queue")] Album myQueueItem, FunctionContext context)
        //</docsnippet_queue_trigger>
        {
            // Use a string array to return more than one message.
            string[] messages = {
                $"Album name = {myQueueItem.Name}",
                $"Album songs = {myQueueItem.Songs.ToString()}"};

            _logger.LogInformation("{msg1},{msg2}", messages[0], messages[1]);

            // Queue Output messages
            return messages;
        }
        //</docsnippet_queue_output_binding>

        /// <summary>
        /// This function demonstrates binding to a single <see cref="QueueMessage"/>.
        /// </summary>
        [Function(nameof(QueueMessageFunction))]
        public void QueueMessageFunction([QueueTrigger("input-queue")] QueueMessage message)
        {
            _logger.LogInformation(message.MessageText);
        }

        /// <summary>
        /// This function demonstrates binding to a single <see cref="BinaryData"/>.
        /// </summary>
        [Function(nameof(QueueBinaryDataFunction))]
        public void QueueBinaryDataFunction([QueueTrigger("input-queue")] BinaryData message)
        {
            _logger.LogInformation(message.ToString());
        }
    }

    public class Album
    {
        public string Id { get; set; }

        public string Name { get; set; }

        public List<string> Songs { get; set; }
    }
}

有关如何配置队列存储输出绑定的端到端示例,请参阅以下文章之一:

以下示例显示了一个 Java 函数,该函数在由 HTTP 请求触发时创建队列消息。

@FunctionName("httpToQueue")
@QueueOutput(name = "item", queueName = "myqueue-items", connection = "MyStorageConnectionAppSetting")
 public String pushToQueue(
     @HttpTrigger(name = "request", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS)
     final String message,
     @HttpOutput(name = "response") final OutputBinding<String> result) {
       result.setValue(message + " has been added.");
       return message;
 }

Java 函数运行时库中,对其值将写入队列存储的参数使用 @QueueOutput 注释。 参数类型应为 OutputBinding<T>,其中 T 是 POJO 的任何本机 Java 类型。

有关如何配置队列存储输出绑定的端到端示例,请参阅以下文章之一:

以下示例显示 HTTP 触发的 TypeScript 函数,该函数为收到的每个 HTTP 请求创建队列项。

import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions';

const queueOutput = output.storageQueue({
    queueName: 'outqueue',
    connection: 'MyStorageConnectionAppSetting',
});

export async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    const body = await request.text();
    context.extraOutputs.set(queueOutput, body);
    return { body: 'Created queue item.' };
}

app.http('httpTrigger1', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    extraOutputs: [queueOutput],
    handler: httpTrigger1,
});

若要输出多条消息,请返回一个数组而不是单个对象。 例如:

import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions';

const queueOutput = output.storageQueue({
    queueName: 'outqueue',
    connection: 'MyStorageConnectionAppSetting',
});

export async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    // <displayInDocs>
    context.extraOutputs.set(queueOutput, ['message 1', 'message 2']);
    // </displayInDocs>
    return { body: 'Created queue item.' };
}

app.http('httpTrigger1', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    extraOutputs: [queueOutput],
    handler: httpTrigger1,
});

以下示例显示 HTTP 触发的 JavaScript 函数,该函数为收到的每个 HTTP 请求创建队列项。

const { app, output } = require('@azure/functions');

const queueOutput = output.storageQueue({
    queueName: 'outqueue',
    connection: 'MyStorageConnectionAppSetting',
});

app.http('httpTrigger1', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    extraOutputs: [queueOutput],
    handler: async (request, context) => {
        const body = await request.text();
        context.extraOutputs.set(queueOutput, body);
        return { body: 'Created queue item.' };
    },
});

若要输出多条消息,请返回一个数组而不是单个对象。 例如:

const { app, output } = require('@azure/functions');

const queueOutput = output.storageQueue({
    queueName: 'outqueue',
    connection: 'MyStorageConnectionAppSetting',
});

app.http('httpTrigger1', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    extraOutputs: [queueOutput],
    handler: async (request, context) => {
        // <displayInDocs>
        context.extraOutputs.set(queueOutput, ['message 1', 'message 2']);
        // </displayInDocs>
        return { body: 'Created queue item.' };
    },
});

有关如何配置队列存储输出绑定的端到端示例,请参阅以下文章之一:

以下代码示例演示了如何从 HTTP 触发的函数输出队列消息。 typequeue 的配置节定义了输出绑定。

{
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "Request",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "Response"
    },
    {
      "type": "queue",
      "direction": "out",
      "name": "Msg",
      "queueName": "outqueue",
      "connection": "MyStorageConnectionAppSetting"
    }
  ]
}

利用此绑定配置,PowerShell 函数可以使用 Push-OutputBinding 创建队列消息。 在此示例中,将通过查询字符串或正文参数创建消息。

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.
$message = $Request.Query.Message
Push-OutputBinding -Name Msg -Value $message
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = 200
    Body = "OK"
})

若要同时发送多条消息,请定义消息数组,并使用 Push-OutputBinding 向队列输出绑定发送消息。

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.
$message = @("message1", "message2")
Push-OutputBinding -Name Msg -Value $message
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = 200
    Body = "OK"
})

有关如何配置队列存储输出绑定的端到端示例,请参阅以下文章之一:

下面的示例演示如何将单个值和多个值输出到存储队列。 无论哪种方式,function.json 所需的配置都是相同的。 该示例取决于是使用 v1 还是 v2 Python 编程模型

import logging
import azure.functions as func

app = func.FunctionApp()

@app.function_name(name="QueueOutput1")
@app.route(route="message")
@app.queue_output(arg_name="msg", 
                  queue_name="<QUEUE_NAME>", 
                  connection="<CONNECTION_SETTING>")
def main(req: func.HttpRequest, msg: func.Out[str]) -> func.HttpResponse:
    input_msg = req.params.get('name')
    logging.info(input_msg)

    msg.set(input_msg)

    logging.info(f'name: {name}')
    return 'OK'

有关如何配置队列存储输出绑定的端到端示例,请参阅以下文章之一:

特性

在 C# 库中定义输出绑定的特性取决于 C# 类库的运行模式。

在独立工作进程中运行时,请使用 QueueOutputAttribute,它采用队列的名称,如以下示例所示:

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using Azure.Storage.Queues.Models;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace SampleApp
{
    public class QueueFunction
    {
        private readonly ILogger<QueueFunction> _logger;

        public QueueFunction(ILogger<QueueFunction> logger)
        {
            _logger = logger;
        }

        //<docsnippet_queue_output_binding>
        //<docsnippet_queue_trigger>
        [Function(nameof(QueueFunction))]
        [QueueOutput("output-queue")]
        public string[] Run([QueueTrigger("input-queue")] Album myQueueItem, FunctionContext context)
        //</docsnippet_queue_trigger>
        {
            // Use a string array to return more than one message.
            string[] messages = {
                $"Album name = {myQueueItem.Name}",
                $"Album songs = {myQueueItem.Songs.ToString()}"};

            _logger.LogInformation("{msg1},{msg2}", messages[0], messages[1]);

            // Queue Output messages
            return messages;
        }
        //</docsnippet_queue_output_binding>

        /// <summary>
        /// This function demonstrates binding to a single <see cref="QueueMessage"/>.
        /// </summary>
        [Function(nameof(QueueMessageFunction))]
        public void QueueMessageFunction([QueueTrigger("input-queue")] QueueMessage message)
        {
            _logger.LogInformation(message.MessageText);
        }

        /// <summary>
        /// This function demonstrates binding to a single <see cref="BinaryData"/>.
        /// </summary>
        [Function(nameof(QueueBinaryDataFunction))]
        public void QueueBinaryDataFunction([QueueTrigger("input-queue")] BinaryData message)
        {
            _logger.LogInformation(message.ToString());
        }
    }

    public class Album
    {
        public string Id { get; set; }

        public string Name { get; set; }

        public List<string> Songs { get; set; }
    }
}

在独立工作进程中运行时,仅支持返回的变量。 不能使用输出参数。

修饰符

仅适用于 Python v2 编程模型。

对于使用修饰器定义的 Python v2 功能,支持 queue_output 上的以下属性:

properties 说明
arg_name 表示函数代码中的队列的变量的名称。
queue_name 队列的名称。
connection 指定如何连接到 Azure 队列的应用设置或设置集合的名称。 请参阅连接

对于使用 function.json 定义的 Python 函数,请参阅“配置”部分。

批注

使用 QueueOutput 注释可以将一条消息编写为函数的输出。 以下示例演示一个用于创建队列消息的 HTTP 触发的函数。

package com.function;
import java.util.*;
import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.*;

public class HttpTriggerQueueOutput {
    @FunctionName("HttpTriggerQueueOutput")
    public HttpResponseMessage run(
            @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request,
            @QueueOutput(name = "message", queueName = "messages", connection = "MyStorageConnectionAppSetting") OutputBinding<String> message,
            final ExecutionContext context) {

        message.setValue(request.getQueryParameters().get("name"));
        return request.createResponseBuilder(HttpStatus.OK).body("Done").build();
    }
}
属性 说明
name 在函数签名中声明参数名称。 触发函数时,此参数的值包含队列消息的内容。
queueName 在存储帐户中声明队列名称。
connection 指向存储帐户连接字符串。

QueueOutput 注释关联的参数类型化为 OutputBinding<T> 实例。

配置

仅适用于 Python v1 编程模型

下表说明了可以在传递给 output.storageQueue() 方法的 options 对象上设置的属性。

properties 说明
queueName 队列的名称。
连接 指定如何连接到 Azure 队列的应用设置或设置集合的名称。 请参阅连接

在本地开发时,需要将应用程序设置添加到 Values 集合中的 local.settings.json 文件中。

下表解释了在 function.json 文件中设置的绑定配置属性。

“function.json”属性 说明
type 必须设置为 queue。 在 Azure 门户中创建触发器时,会自动设置此属性。
direction 必须设置为 out。 在 Azure 门户中创建触发器时,会自动设置此属性。
name 表示函数代码中的队列的变量的名称。 设置为 $return 可引用函数返回值。
queueName 队列的名称。
连接 指定如何连接到 Azure 队列的应用设置或设置集合的名称。 请参阅连接

在本地开发时,请将应用程序设置添加到 Values 集合的 local.settings.json 文件

有关完整示例,请参阅示例部分

使用情况

队列输出绑定的用法取决于扩展包版本,以及函数应用中使用的 C# 形式,可以是以下形式之一:

独立工作进程类库的已编译 C# 函数在独立于运行时的进程中运行。

选择一个版本以查看模式和版本的使用情况详细信息。

如果希望函数写入单个消息,队列输出绑定可以绑定到以下类型:

类型 说明
string 消息内容即字符串。 当消息为简单文本时使用。
byte[] 消息的字节数。
JSON 可序列化类型 表示 JSON 消息内容的对象。 函数尝试将普通旧 CLR 对象 (POCO) 类型序列化为 JSON 数据。

如果希望函数写入多个消息,队列输出绑定可以绑定到以下类型:

类型 说明
T[],其中 T 是单消息类型之一 包含多个消息的内容的数组。 每个条目表示一个消息。

对于其他输出方案,请直接创建和使用 Azure.Storage.Queues 中的类型。

可使用两个选项通过 QueueOutput 注释将数据从函数写入队列:

  • 返回值:通过将注释应用于函数本身,函数的返回值将写入到队列中。

  • 命令性:若要显式设置消息值,请将注释应用于 OutputBinding<T> 类型的特定参数,其中 T 是 POJO 或任何本机 Java 类型。 使用此配置时,将值传递给 setValue 方法就会将值写入队列。

通过直接返回值或使用 context.extraOutputs.set() 来访问输出队列项。 可对队列项有效负载使用字符串或 JSON 可序列化对象。

通过 Push-OutputBinding 可以输出到队列消息,你在其中传递的参数与 function.json 文件中绑定的 name 参数指定的名称匹配。

可以通过两个选项将数据从函数写入到已配置的队列:

  • 返回值:将 function.json 中的 name 属性 设置为 $return。 使用此配置时,函数的返回值将作为队列存储消息保留。

  • 命令性:将值传递给声明为 Out 类型的参数的 set 方法。 传递给 set 的值将作为队列存储消息保留。

连接

connection 属性是对环境配置的引用,它指定应用应如何连接到 Azure 队列。 它可能指定:

如果配置的值既是单个设置的完全匹配,也是其他设置的前缀匹配,则使用完全匹配。

连接字符串

若要获取连接字符串,请执行管理存储帐户访问密钥中显示的步骤。

此连接字符串应存储在应用程序设置中,其名称与绑定配置的 connection 属性指定的值匹配。

如果应用设置名称以“AzureWebJobs”开始,则只能在此处指定该名称的余下部分。 例如,如果将 connection 设置为“MyStorage”,Functions 运行时将会查找名为“AzureWebJobsMyStorage”的应用设置。如果将 connection 留空,Functions 运行时将使用应用设置中名为 AzureWebJobsStorage 的默认存储连接字符串。

基于标识的连接

如果使用 5.x 或更高版本的扩展,则无需将连接字符串与机密配合使用,可以让应用使用 Azure Active Directory 标识。 要使用标识,需要定义公共前缀下的设置,该前缀映射到触发器和绑定配置中的 connection 属性。

如果将 connection 设置为“AzureWebJobsStorage”,请参阅使用标识连接到主机存储。 对于所有其他连接,扩展需要以下属性:

属性 环境变量模板 说明 示例值
队列服务 URI <CONNECTION_NAME_PREFIX>__queueServiceUri1 要连接到的队列服务的数据平面 URI,使用 HTTPS 方案。 https://<storage_account_name>.queue.core.chinacloudapi.cn

1 <CONNECTION_NAME_PREFIX>__serviceUri 可以用作别名。 如果同时提供了两个窗体,则会使用 queueServiceUri 窗体。 如果要跨 Blob、队列和/或表使用总体连接配置,则无法使用 serviceUri 窗体。

可以设置其他属性来自定义连接。 请参阅基于标识的连接的通用属性

在 Azure Functions 服务中托管时,基于标识的连接将使用托管标识。 默认情况下使用系统分配的标识,但可以使用 credentialclientID 属性来指定用户分配的标识。 请注意,不支持为用户分配的标识配置资源 ID。 在其他上下文(如本地开发)中运行时,将改用开发人员标识,尽管可以进行自定义。 请参阅使用基于标识的连接进行本地开发

向标识授予权限

无论使用何种标识,都必须具有执行所需操作的权限。 需要使用内置角色或者提供这些权限的自定义角色在 Azure RBAC 中分配角色

重要

某些权限可能由并非所有上下文都需要的目标服务公开。 尽可能遵循最低权限原则,仅授予标识所需的权限。 例如,如果应用只需要从数据源进行读取即可,则使用仅具有读取权限的角色。 分配一个也具有该服务写入权限的角色并不恰当,因为对于读取操作来说,写入是多余的权限。 同样,你也希望确保角色分配的范围仅限于需要读取的资源。

你将需要创建一个角色分配,以便在运行时提供对队列的访问权限。 所有者等管理角色还不够。 下表显示了在正常操作中使用队列存储扩展时建议使用的内置角色。 根据所编写的代码,应用程序可能需要具有其他权限。

绑定类型 内置角色示例
触发器 存储队列数据读取者存储队列数据消息处理者
输出绑定 存储队列数据参与者存储队列数据消息发送方

异常和返回代码

绑定 参考
队列 队列错误代码
Blob、表、队列 存储错误代码
Blob、表、队列 故障排除

后续步骤