Упражнение. Добавление логики в приложение-функцию

Завершено

Здесь мы продолжим работу с примером привода, добавив логику для службы контроля температуры. В частности, мы настроим получение данных через HTTP-запрос.

Требования к функции

Прежде всего давайте определим некоторые требования для нашей логики:

  • температура от 0 до 25 градусов получает флаг ОК;
  • температура от 25 до 50 градусов получает флаг ОСТОРОЖНО;
  • температура выше 50 градусов получает флаг DANGER.

Добавление функции в приложение-функцию

Как уже говорилось на предыдущем уроке, предоставляемые Azure шаблоны помогут вам быстро к создавать функции. В этом уроке HttpTrigger шаблон используется для реализации службы температуры.

  1. В предыдущем упражнении вы развернули приложение-функцию и открыли ее. Если она еще не открыта, ее можно открыть на главной странице, выбрав Все ресурсы, а затем выбрав приложение-функцию с именем вида escalator-functions-xxx.

  2. На экране приложения-функции на вкладке "Функции" выберите "Создать" в портал Azure. Откроется панель Создание функции.

  3. В разделе Выберите шаблон выберите Триггер HTTP.

  1. Нажмите кнопку создания. HttpTrigger1 создается и отображается в области функции HttpTrigger1.

  2. В меню "Разработка" слева выберите Код и тестирование. Откроется редактор кода, в котором отобразится содержимое файла кода index.js для функции. Следующий фрагмент содержит код по умолчанию, который автоматически создается шаблоном HTTP.

    module.exports = async function (context, req) {
        context.log('JavaScript HTTP trigger function processed a request.');
    
        const name = (req.query.name || (req.body && req.body.name));
        const responseMessage = name
            ? "Hello, " + name + ". This HTTP triggered function executed successfully."
            : "This HTTP triggered function executed successfully. Pass a name on the query string or in the request body for a personalized response.";
    
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: responseMessage
        };
    }
    

    Эта функция ожидает передачи имени или через строку HTTP-запроса, или в самом тексте запроса. В ответ функция возвращает сообщение Привет, <имя>. Функция, активируемая по HTTP, успешно выполнена., возвращая имя, отправленное в запросе.

    В раскрывающемся списке исходного файла выберите файл function.json, содержимое которого выглядит так, как в коде ниже.

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

    Этот файл конфигурации объявляет, что функция выполняется при получении HTTP-запроса. Выходная привязка объявляет, что ответ отправляется в виде HTTP-ответа.

  1. В разделе Сведения о шаблоне в поле Новая функция введите DriveGearTemperatureService. Оставьте для параметра Уровень авторизации значение Функция и затем нажмите кнопку Создать, чтобы создать функцию. Откроется панель "Обзор" для функции DriveGearTemperatureService.

  2. В меню "Функция" выберите пункт Код и тестирование. Откроется редактор кода с содержимым файла кода run.ps1. Следующий фрагмент содержит код по умолчанию, который автоматически создается шаблоном.

    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
    }
    
    $body = "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
    
    if ($name) {
        $body = "Hello, $name. This HTTP triggered function executed successfully."
    }
    
    # Associate values to output bindings by calling 'Push-OutputBinding'.
    Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
        StatusCode = [HttpStatusCode]::OK
        Body = $body
    })
    

    Эта функция ожидает передачи имени или через строку HTTP-запроса, или в самом тексте запроса. Функции HTTP должны создавать ответ путем записи в выходную привязку, для чего в PowerShell служит командлет Push-OutputBinding. Функция возвращает сообщение Hello, $name, составляя его на основе полученного в запросе имени.

  3. Чтобы просмотреть конфигурацию функции, из раскрывающегося меню "Источник" выберите файл function.json, содержимое которого выглядит примерно так:

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

    Такая конфигурация означает, что функция выполняется при получении HTTP-запроса. Выходная привязка объявляет, что ответ отправляется в виде HTTP-ответа.

Проверка функции

Совет

Средство командной строки cURL можно использовать для отправки и получения файлов. Оно входит в состав Linux, macOS и Windows 10, а также доступно для большинства других операционных систем. cURL поддерживает множество протоколов, в том числе HTTP, HTTPS, FTP, FTPS, SFTP, LDAP, TELNET, SMTP, POP3 и другие. Дополнительные сведения см. по следующим ссылкам.

Чтобы протестировать функцию, отправьте HTTP-запрос на URL-адрес функции, запустив cURL в командной строке.

  1. Разверните фрейм Журналы в нижней части панели функции для триггеров. Выберите Журналы файловой системы в раскрывающемся списке в верхней части кадра журналов. Кадр журнала должен начать каждую минуту принимать уведомления о трассировке.

  2. Чтобы найти URL-адрес конечной точки функции, на панели команд выберите Получить URL-адрес функции, как показано на следующем рисунке. Сохраните эту ссылку, выбрав значок Копировать в буфер обмена в конце URL-адреса. Сохраните эту ссылку в Блокноте или аналогичном приложении для последующего использования.

    Screenshot of the Azure portal showing the function editor, with the Get function URL button highlighted.

  3. Откройте командную строку и запустите cURL, чтобы отправить HTTP-запрос на URL-адрес функции. Имейте в виду использование URL-адреса, скопированного на предыдущем шаге.

    curl "<your-https-url>"
    

    Совет

    Возможно, потребуется упаковать URL-адрес в кавычки, чтобы избежать проблем с специальными символами в URL-адресе.
    Если вы находитесь в Windows, выполните команду cURL из командной строки. PowerShell имеет команду curl , но это псевдоним для Invoke-WebRequest, который не совпадает cURLс .

    Ответ должен выглядеть следующим образом.

    This HTTP triggered function executed successfully. Pass a name on the query string or in the request body for a personalized response.
    

    Теперь передайте имя в запросе. Для этого необходимо добавить параметр строки запроса с именем name URL-адреса. В следующем примере добавляется параметр name=Azureстроки запроса.

    curl "<your-https-url>&name=Azure"
    

    Ответ должен выглядеть следующим образом.

    Hello, Azure. This HTTP triggered function executed successfully.
    

    Функция успешно выполнена и вернула имя, переданное в запросе.

Защита триггеров HTTP

Триггеры HTTP позволяют с помощью ключей API блокировать вызовы от неизвестных объектов, требуя наличие ключа в каждом запросе. При создании функции нужно выбрать уровень авторизации. По умолчанию он имеет значение Function, для которого требуется ключ API для конкретной функции. Также можно задать для Администратор использовать глобальный главный ключ или анонимный, чтобы указать, что ключ не требуется. Уровень авторизации можно изменить и после создания функции, открыв ее свойства.

При создании этой функции вы указали параметр Функция. Это значит, что при отправке HTTP-запроса нужно предоставить ключ. Его можно отправить как параметр строки запроса с именем code. Или используйте предпочтительный метод и передайте его в качестве заголовка HTTP с именем x-functions-key.

  1. Чтобы найти функцию и главные ключи, в меню приложения-функции в разделе Разработка выберите Ключи функции. Откроется панель "Ключи функции" для вашей функции.

  2. По умолчанию значение ключа функции скрыто. Отображение значения ключа функции по умолчанию, выбрав "Показать значение". Скопируйте содержимое поля "Значение" в буфер обмена, а затем сохраните этот ключ в Блокнот или аналогичном приложении для последующего использования.

    Screenshot showing the Function Keys pane with the revealed function key highlighted.

  3. Чтобы проверить функцию с помощью ключа функции, откройте командную строку и запустите cURL, чтобы отправить HTTP-запрос в URL-адрес функции. Замените <your-function-key> сохраненным значением ключа функции и замените <your-https-url> URL-адрес функции.

    curl --header "Content-Type: application/json" --header "x-functions-key: <your-function-key>" --request POST --data "{\"name\": \"Azure Function\"}" <your-https-url>
    
  4. Убедитесь, что команда cURL имеет следующие значения:

    • Добавляется значение заголовка Content-Type типа application/json.
    • Ключ функции передается как значение заголовка x-functions-key.
    • Используется запрос POST.
    • Передана функция Azure с URL-адресом для функции.
  5. Проверьте журналы.

    В области Код и тест должен открыться сеанс, отображающий выходные данные файла журнала (убедитесь, что журналы файловой системы выбраны в раскрывающемся списке в верхней части панели Журналы). Файл журнала обновляется с учетом состояния вашего запроса, который должен выглядеть примерно так:

```output
2022-02-16T22:34:10.473 [Information] Executing 'Functions.HttpTrigger1' (Reason='This function was programmatically called via the host APIs.', Id=4f503b35-b944-455e-ba02-5205f9e8b47a)
2022-02-16T22:34:10.539 [Information] JavaScript HTTP trigger function processed a request.
2022-02-16T22:34:10.562 [Information] Executed 'Functions.HttpTrigger1' (Succeeded, Id=4f503b35-b944-455e-ba02-5205f9e8b47a, Duration=114ms)
```
```output
2022-02-16T21:07:11.340 [Information] INFORMATION: PowerShell HTTP trigger function processed a request.
2022-02-16T21:07:11.449 [Information] Executed 'Functions.DriveGearTemperatureService' (Succeeded, Id=25e2edc3-542f-4629-a152-cf9ed99680d8, Duration=1164ms)
```

Добавление бизнес-логики в функцию

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

Наша функция ожидает на вход массив с показаниями температуры. В следующем фрагменте JSON приведен пример текста запроса, который отправляется в эту функцию. Каждая запись reading содержит идентификатор, отметку времени и значение температуры.

{
    "readings": [
        {
            "driveGearId": 1,
            "timestamp": 1534263995,
            "temperature": 23
        },
        {
            "driveGearId": 3,
            "timestamp": 1534264048,
            "temperature": 45
        },
        {
            "driveGearId": 18,
            "timestamp": 1534264050,
            "temperature": 55
        }
    ]
}

Давайте заменим стандартный код нашей функции следующим кодом, чтобы реализовать требуемую бизнес-логику.

В области функции HttpTrigger1 откройте файл index.js и замените его приведенным ниже кодом. После внесения этого изменения на панели команд нажмите кнопку Сохранить, чтобы сохранить обновления в файле.

module.exports = function (context, req) {
    context.log('Drive Gear Temperature Service triggered');
    if (req.body && req.body.readings) {
        req.body.readings.forEach(function(reading) {

            if(reading.temperature<=25) {
                reading.status = 'OK';
            } else if (reading.temperature<=50) {
                reading.status = 'CAUTION';
            } else {
                reading.status = 'DANGER'
            }
            context.log('Reading is ' + reading.status);
        });

        context.res = {
            // status: 200, /* Defaults to 200 */
            body: {
                "readings": req.body.readings
            }
        };
    }
    else {
        context.res = {
            status: 400,
            body: "Please send an array of readings in the request body"
        };
    }
    context.done();
};

Мы добавили очень простую логику. Мы проходим через массив и задаем состояние ОК, ОСТОРОЖНО или ОПАСНО в зависимости от значения поля "Температура". Обновленный массив показаний со значениями состояния возвращается обратно.

Обратите внимание на операторы Log, которые можно увидеть, развернув область Журналы в нижней части панели. При выполнении функции эти инструкции добавляют сообщения в окно журналов.

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

using namespace System.Net

param($Request, $TriggerMetadata)

Write-Host "Drive Gear Temperature Service triggered"

$readings = $Request.Body.Readings
if ($readings) {
    foreach ($reading in $readings) {
        if ($reading.temperature -le 25) {
            $reading.Status = "OK"
        }
        elseif ($reading.temperature -le 50) {
            $reading.Status = "CAUTION"
        }
        else {
            $reading.Status = "DANGER"
        }

        Write-Host "Reading is $($reading.Status)"
    }

    $status = [HttpStatusCode]::OK
    $body = $readings
}
else {
    $status = [HttpStatusCode]::BadRequest
    $body = "Please send an array of readings in the request body"
}

Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = $status
    Body = $body
})

Мы добавили очень простую логику. Мы проходим через массив и задаем состояние ОК, ОСТОРОЖНО или ОПАСНО в зависимости от значения поля "Температура". Обновленный массив показаний со значениями состояния возвращается обратно.

Обратите внимание на вызовы командлета Write-Host. При выполнении функции эти инструкции добавляют сообщения в окно журналов.

Тестирование бизнес-логики

Мы будем использовать функцию Тест/Запуск на странице Разработка>Код и тестирование для тестирования функции.

  1. На вкладке Входные данные замените содержимое текстового поля Текст приведенными ниже кодом, чтобы создать пример запроса.

    {
        "readings": [
            {
                "driveGearId": 1,
                "timestamp": 1534263995,
                "temperature": 23
            },
            {
                "driveGearId": 3,
                "timestamp": 1534264048,
                "temperature": 45
            },
            {
                "driveGearId": 18,
                "timestamp": 1534264050,
                "temperature": 55
            }
        ]
    }
    
  2. Выберите Выполнить. На вкладке Выходные данные отображается код отклика HTTP (200 OK) и содержимое. Чтобы просмотреть сообщения журнала, откройте вкладку "Журналы" в нижнем всплывающем меню панели (если она еще не открыта). На следующем рисунке показан пример ответа в области вывода и сообщений в области Журналы.

    Screenshot of the Azure function editor, with the Test and Logs tabs showing.

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

  3. В меню "Разработка" слева выберите Мониторинг, чтобы убедиться, что запрос был зарегистрирован в Application Insights. Для функции появится панель Мониторинг.

    Вкладка "Вызовы" на панели отображает трассировки вызовов для каждого вызова функции. Выберите значение Date(UTC) для одного из вызовов и просмотрите сведения о выполнении функции.