Бөлісу құралы:


Подключение Azure Functions к Azure Storage с помощью средств командной строки

В этой статье вы интегрируете очередь Azure Storage с функцией и учетной записью хранилища, созданной в предыдущем руководстве по быстрому старту. Чтобы реализовать такую интеграцию, используется выходная привязка, которая записывает в сообщение очереди данные из HTTP-запроса. Завершение этой статьи не подразумевает дополнительных затрат и стоит столько же, сколько несколько центов США, потраченных на предыдущее краткое руководство. Дополнительные сведения о привязках см. в разделе концепции триггеров и привязок в Azure Functions.

Настройка локальной среды

Прежде чем приступать к работе, вы должны сначала ознакомиться с руководством Quickstart: создание проекта Azure Functions из командной строки. Если вы уже очистили ресурсы в конце этой статьи, выполните действия, чтобы повторно создать приложение-функцию и связанные ресурсы в Azure.

Перед началом работы необходимо ознакомиться со статьёй Quickstart: создание проекта Azure Functions из командной строки. Если вы уже очистили ресурсы в конце этой статьи, выполните действия, чтобы повторно создать приложение-функцию и связанные ресурсы в Azure.

Перед началом работы необходимо завершить изучение статьи Quickstart: создание проекта Azure Functions из командной строки. Если вы уже очистили ресурсы в конце этой статьи, выполните действия, чтобы повторно создать приложение-функцию и связанные ресурсы в Azure.

Перед началом работы необходимо выполнить статью Быстрый старт: создание проекта Azure Functions из командной строки. Если вы уже очистили ресурсы в конце этой статьи, выполните действия, чтобы повторно создать приложение-функцию и связанные ресурсы в Azure.

Перед началом работы необходимо ознакомиться со статьей Быстрый старт: создание проекта Azure Functions из командной строки. Если вы уже очистили ресурсы в конце этой статьи, выполните действия, чтобы повторно создать приложение-функцию и связанные ресурсы в Azure.

Перед началом работы необходимо ознакомиться со статьёй Quickstart: создание проекта Azure Functions из командной строки. Если вы уже очистили ресурсы в конце этой статьи, выполните действия, чтобы повторно создать приложение-функцию и связанные ресурсы в Azure.

Извлечение строки подключения Azure Storage

Внимание

В этой статье показано, как подключиться к учетной записи Azure Storage с помощью connection string, содержащей общий секретный ключ. Использование connection string упрощает проверку обновлений данных в учетной записи storage. Для обеспечения оптимальной безопасности следует использовать управляемые удостоверения, подключаясь к учетной записи хранения. Дополнительные сведения см. в руководстве разработчика по подключениям .

Ранее вы создали учетную запись Azure Storage для использования приложения-функции. Строка подключения для этой учетной записи безопасно хранится в параметрах приложения в Azure. Скачав параметр в файл local.settings.json, можно использовать подключение для записи в очередь Storage в той же учетной записи при локальном запуске функции.

  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 в окне терминала, чтобы добавить пакет расширения Storage в project.

dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues --prerelease

Теперь вы можете добавить в ваш проект привязку к хранилищу.

Добавление определения выходной привязки к функции

Хотя функция может иметь только один триггер, она может иметь несколько входных и выходных привязок, что позволяет подключаться к другим службам и ресурсам Azure без написания пользовательского кода интеграции.

При использовании модели программирования Node.js версии 4 атрибуты привязки определяются непосредственно в файле ./src/functions/HttpExample.js . В предыдущем быстром старте ваш файл уже содержит HTTP биндинг, определенный методом app.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 версии 4 атрибуты привязки определяются непосредственно в файле ./src/functions/HttpExample.js . В предыдущем быстром старте ваш файл уже содержит HTTP биндинг, определенный методом app.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 в папке функции. В предыдущем кратком руководстве в файле function.json, расположенном в папке HttpExample, содержатся две привязки в коллекции bindings.

При использовании модели программирования Python версии 2 атрибуты привязки определяются непосредственно в файле 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 Storage из этой функции, добавьте декоратор queue_output в код своей функции.

@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")

В декораторе arg_name определяет параметр привязки, на который ссылается код, queue_name — имя очереди, в которую записывается привязка, и connection — это имя параметра приложения, содержащего connection string для учетной записи Storage. В кратких руководствах используется та же учетная запись хранилища, что и функциональное приложение, которое указано в параметре AzureWebJobsStorage (файла local.settings.json). Если queue_name не существует, то при первом использовании привязка создаст этот параметр.

"bindings": [
  {
    "authLevel": "function",
    "type": "httpTrigger",
    "direction": "in",
    "name": "Request",
    "methods": [
      "get",
      "post"
    ]
  },
  {
    "type": "http",
    "direction": "out",
    "name": "Response"
  }
]

Как записать в очередь Azure Storage:

  • Добавьте свойство extraOutputs в конфигурацию привязки

    {
        methods: ['GET', 'POST'],
        extraOutputs: [sendToQueue], // add output binding to HTTP trigger
        authLevel: 'anonymous',
        handler: () => {}
    }
    
  • Добавление функции над вызовом output.storageQueueapp.http

    const sendToQueue: StorageQueueOutput = output.storageQueue({
      queueName: 'outqueue',
      connection: 'AzureWebJobsStorage',
    });
    

Вторая привязка в коллекции называется res. Эта привязка http является выходной привязкой (out), которая используется для записи HTTP-ответа.

Чтобы записать в очередь Azure Storage из этой функции, добавьте привязку out типа queue с именем msg, как показано в приведенном ниже коде:

    {
      "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 и указать имя подключения Azure Storage (из файла local.settings.json) в connection.

В project C# привязки определяются как атрибуты привязки в методе функции. Конкретные определения зависят от того, выполняется ли приложение в процессе (библиотека классов C#) или в изолированном рабочем процессе.

Откройте файл HttpExample.cs project и добавьте следующий класс MultiResponse:

public class MultiResponse
{
    [QueueOutput("outqueue", Connection = "AzureWebJobsStorage")]
    public string[] Messages { get; set; }
    public IActionResult HttpResponse { get; set; }
}

Класс MultiResponse позволяет записывать в очередь хранения с именем outqueue и отправлять сообщение об успешном выполнении HTTP. Так как атрибут QueueOutput применяется к массиву строк, в очередь можно отправить несколько сообщений.

Свойство Connection задает строку подключения для учетной записи хранилища. В этом случае можно опустить Connection, так как вы уже используете учетную запись storage по умолчанию.

В проекте Java привязки определяются как аннотации привязки на методе функции. Затем на основе этих заметок автоматически создается файл function.json.

Перейдите к расположению кода функции в разделе src/main/java откройте файл Function.java project и добавьте следующий параметр в определение метода 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 и записывала сообщения в очередь.

Обновите HttpExample\function_app.py, чтобы он соответствовал следующему коду, добавив параметр msg в определение функции и msg.set(name) в выражении if name:.

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 записывает строковое сообщение в очередь. В этом случае name передается в функцию в строке запроса URL-адреса.

Добавьте код, который с использованием объекта выходной привязки на 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 для записи текста в очередь с помощью привязки выходных данных 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
})

Замените существующий Run метод следующим кодом:

[Function("HttpExample")]
public MultiResponse Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req)
{
    _logger.LogInformation("C# HTTP trigger function processed a request.");

    var message = "Welcome to Azure Functions!";

    // Return a response to both HTTP trigger and storage output binding.
    return new MultiResponse()
    {
        // Write a single message.
        Messages = new string[] { message },
        HttpResponse = new OkObjectResult(message)
    };
}

Теперь для записи в выходную привязку из кода функции вы можете использовать новый параметр msg. Добавьте следующую строку кода перед успешным ответом, чтобы добавить значение name к выходной привязке msg.

msg.setValue(name);

При использовании выходной привязки вам не нужно использовать код пакета SDK Azure Storage для проверки подлинности, получения ссылки на очередь или записи данных. Эти задачи выполняются средой выполнения функций и выходной привязкой очереди за вас.

Теперь метод 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();
    }
}

Обновление тестов

Поскольку архетип также создает набор тестов, необходимо обновить эти тесты для обработки нового параметра msg в сигнатуре метода run.

Перейдите к расположению тестового кода в src/test/java, откройте файл Function.java project и замените строку кода в //Invoke следующим кодом:

@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);
final HttpResponseMessage ret = new Function().run(req, msg, context);

Обратите внимание, что не нужно писать код для проверки подлинности, получения ссылки на очередь или записи данных. Все эти задачи интеграции удобно обрабатываются в среде выполнения Azure Functions и привязке выходных данных к очереди.

Локальное выполнение функции

  1. Запустите функцию, запуская локальный узел среды выполнения Azure Functions из папки LocalFunctionProj.

    func start
    

    Ближе к концу выходных данных появятся следующие строки:

    Скриншот окна терминала с выводом при локальном выполнении функции.

    Примечание.

    Если HttpExample не отображается, как показано выше, вероятно, вы запустили хост вне корневой папки проекта. В этом случае используйте Ctrl+C, чтобы остановить хост, перейти в корневую папку проекта и снова запустить предыдущую команду.

  2. Скопируйте URL-адрес вашей HTTP-функции из этого вывода в браузер и добавьте к нему строку запроса ?name=<YOUR_NAME>, чтобы получить полный URL-адрес, например http://localhost:7071/api/HttpExample?name=Functions. Браузер должен отобразить ответное сообщение, которое повторяет значение вашей строки запроса. Терминал, в котором вы запустили project также отображает выходные данные журнала при отправке запросов.

  3. Когда завершите работу, нажмите Ctrl + C и введите y, чтобы остановить хост функций.

Просмотр сообщения в очереди Azure Storage

Очередь можно просмотреть в Azure portal или в Microsoft Azure Storage Explorer. Вы также можете просмотреть очередь в Azure CLI, как описано в следующих шагах:

  1. Откройте файл функции проекта local.setting.json и скопируйте значение строки подключения. В окне терминала или командной строки выполните следующую команду, чтобы создать переменную среды с именем AZURE_STORAGE_CONNECTION_STRING и вставьте конкретную connection string вместо <MY_CONNECTION_STRING>. (Эта переменная среды означает, что вам не нужно предоставлять строку подключения каждой последующей команде с помощью аргумента --connection-string.)

    export AZURE_STORAGE_CONNECTION_STRING="<MY_CONNECTION_STRING>"
    
  2. (Необязательно) Используйте команду az storage queue list для просмотра очередей Storage в учетной записи. В выходных данных этой команды должна быть очередь с именем 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 Storage, вы можете повторно развернуть проект, чтобы обновить конечную точку, работающую в Azure.

В папке LocalFunctionsProj используйте команду func azure functionapp publish для повторного развертывания project, заменив<APP_NAME> именем приложения.

func azure functionapp publish <APP_NAME>

В локальной папке project используйте следующую команду Maven, чтобы повторно опубликовать project:

mvn azure-functions:deploy

Проверка в Azure

  1. Как и в предыдущем кратком руководстве, используйте браузер или cURL для тестирования функции после повторного развертывания.

    Скопируйте полный URL-адрес вызова Invoke URL, показанный в выходных данных команды publish, в адресную строку браузера, добавив параметр запроса &name=Functions. В браузере должны отображаться выходные данные, аналогичные данным при локальном запуске функции.

  2. Проверьте очередь Storage еще раз, как описано в предыдущем разделе, чтобы убедиться, что она содержит новое сообщение, записанное в очередь.

Очистка ресурсов

После завершения выполните следующую команду, чтобы удалить группу ресурсов и все содержащиеся в ней ресурсы, чтобы избежать дополнительных затрат.

az group delete --name AzureFunctionsQuickstart-rg

Следующие шаги

Вы обновили функцию, активированную HTTP, чтобы записывать данные в очередь хранилища. Теперь вы можете узнать больше о разработке функций из командной строки с помощью основных средств и Azure CLI: