Поделиться через


Подключение Функций Azure к службе хранилища Azure с помощью средств командной строки

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

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

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

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

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

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

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

Перед началом работы необходимо выполнить статью, краткое руководство. Создание проекта Функции 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 версии 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 из этой функции, добавьте queue_output декоратор в код функции:

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

В декораторе arg_name идентифицирует параметр привязки, на который ссылается код, является именем очереди, queue_name в которую записывается привязка, и connection является именем параметра приложения, содержащего строка подключения для учетной записи хранения. В кратком руководстве используется та же учетная запись хранения, что и приложение-функция, которое находится в 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:

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

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

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

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

Чтобы записать в очередь службы хранилища Azure данные из этой функции, добавьте привязку 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 (из файла local.settings.json).connection

В проекте 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 triggers and bindings (Основные понятия триггеров и привязок в Функциях Azure) и в разделе о конфигурации выходных данных очереди.

Добавление кода для использования выходной привязки

Определив привязку очереди, можно обновлять функцию, чтобы она получала выходной параметр 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
})

Замените класс 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);

После использования выходной привязки вам для проверки подлинности, получения ссылки на очередь или записи данных больше не потребуется код пакета SDK службы хранилища Azure. Вместо вас эти задачи будут выполнены выходной привязкой очереди и средой выполнения функции.

Теперь метод 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 и замените строку кода в //Invoke следующим кодом:

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

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

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

  1. Выполните функцию, запустив локальное хост-приложение среды выполнения Функций Azure из папки LocalFunctionProj.

    func start
    

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

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

    Примечание.

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

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

  3. Когда все будет готово, нажмите клавиши CTRL+C и введите y, чтобы отключить хост-приложение функции.

Совет

Во время запуска узел скачивает и устанавливает расширение привязки хранилища и другие расширения привязки Майкрософт. Эта установка происходит, потому что расширения привязки включены по умолчанию в файле host.json со следующими свойствами:

{
    "version": "2.0",
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[1.*, 2.0.0)"
    }
}

Если возникнут ошибки, связанные с расширениями привязки, убедитесь, что указанные выше свойства есть в файле host.json.

Просмотр сообщения в очереди службы хранилища Azure

Очередь можно просмотреть на портале Azure или в Обозревателе службы хранилища Azure. Очередь также можно просмотреть в интерфейсе командной строки Azure. Для этого выполните приведенные ниже шаги:

  1. Откройте файл local.setting.json проекта функций и скопируйте значение строки подключения. В окне терминала или командной строки выполните следующую команду, чтобы создать переменную среды с именем AZURE_STORAGE_CONNECTION_STRING. Вставьте нужную строку подключения вместо <MY_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-адрес вызова Invoke URL, показанный в выходных данных команды publish, в адресную строку браузера, добавив параметр запроса &name=Functions. В браузере должны отображаться выходные данные, аналогичные данным при локальном запуске функции.

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

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

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

az group delete --name AzureFunctionsQuickstart-rg

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

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