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

Завершено

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

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

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

  • Температура от 0 до 25 градусов должна быть помечена как ОК.
  • Температура выше 25 до 50 градусов должна быть помечена как ПРЕДУПРЕЖДЕНИЕ.
  • Температура выше 50 градусов должна быть помечена как ОПАСНОСТЬ.

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

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

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

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

  3. В разделе "Выбор шаблона" выберите триггер HTTP и нажмите кнопку "Далее".

  1. Оставьте имя функциикак HttpTrigger1 и уровень авторизации как функция и нажмите кнопку "Создать". Функция 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-запроса, или в самом тексте запроса. Функция отвечает, возвращая сообщение Hello, <имя>. Эта функция, активировающая 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-адрес функции", как показано на следующем рисунке. Сохраните ссылку _master (ключ узла), выбрав значок копирования в буфер обмена в конце URL-адреса. Сохраните эту ссылку в Блокноте или аналогичном приложении для последующего использования.

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

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

    curl "<your-https-url>"
    

    Совет

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

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

    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 для конкретной функции. Кроме того, администратор может использовать глобальный главный ключ или анонимный, чтобы указать, что ключ не требуется. Уровень авторизации можно изменить и после создания функции, открыв ее свойства.

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

  1. Чтобы найти ключи функции, откройте меню "Код + тест ", выбрав имя функции (например , HttpTriger1) на вкладке "Функции " в меню "Обзор ". Затем перейдите на вкладку "Ключи функций ".

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

    Снимок экрана: панель

  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 является примером текста запроса, который мы отправим в нашу функцию. Имя массива может немного отличаться для JavaScript или PowerShell, но каждая запись в массиве имеет идентификатор, метку времени и температуру.

{
    "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 инструкции при развертывании журналов в нижней части области. При выполнении функции эти инструкции добавляют сообщения в окно журналов.

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

Мы будем использовать функцию test/Run в коде разработчика>и тесте для тестирования нашей функции.

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

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

Откройте файл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. При выполнении функции эти инструкции добавляют сообщения в окно журналов.

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

Мы будем использовать функцию test/Run в коде разработчика>и тесте для тестирования нашей функции.

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

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

    Снимок экрана редактора функций Azure с вкладками

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