练习 - 向函数应用添加逻辑

已完成

让我们继续介绍齿轮传动示例,并添加温度服务的逻辑。 具体而言,我们将从 HTTP 请求接收数据。

函数要求

首先,我们需要为逻辑定义一些要求:

  • 从 0 到 25 度的温度应被标记为“正常”。
  • 25 度以上至 50 度的温度应被标记为“警告”。
  • 超过 50 度的温度应被标记为“危险”。

向函数应用添加一个函数

如之前单元中所述,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 请求查询字符串或作为请求正文的一部分进行传递。 函数通过返回消息“你好,<name>。此 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 函数必须通过写入其输出绑定生成响应,该绑定是使用 Push-OutputBinding cmdlet 在 PowerShell 函数中实现的。 此函数会返回消息“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 等。 有关详细信息,请参阅以下链接:

若要测试函数,可以在命令行上使用 cURL 将 HTTP 请求发送至函数 URL。

  1. 展开触发器函数窗格底部的“日志”框架。 在日志框架顶部的下拉列表中选择“文件系统日志”。 日志框架应开始每分钟积累跟踪通知。

  2. 若要查找函数的终结点 URL,请在命令栏中选择“获取函数 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 密钥,通过要求每个请求都具备密钥来阻止未知的调用方。 在创建函数时,选择“授权级别”。 默认情况下,它设置为函数,这需要特定于函数的 API 密钥。 也可将其设置为“管理员”以使用全局 master 密钥,或者将其设置为“匿名”以指示无需密钥。 还可以在创建函数后通过函数属性来更改授权级别。

由于在创建此函数时指定的授权级别是“函数”,所以需要在发送 HTTP 请求时提供密钥。 可以将它作为名为 code 的查询字符串参数发送。 或者,使用偏好的方法,将其作为名为 x-functions-key 的 HTTP 标头传递。

  1. 若要查找函数和主密钥,请在“函数应用”菜单中的“开发人员”下,选择“函数密钥”。 系统随即打开函数的“函数密钥”窗格。

  2. 默认情况下,函数密钥值处于隐藏状态。 通过选择“显示值”来显示默认函数密钥值。 将“值”字段的内容复制到剪贴板,然后将此密钥存储在记事本或类似应用中供以后使用。

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

  3. 若要使用函数密钥测试函数,请打开命令提示符并运行 cURL 以向函数 URL 发送 HTTP 请求。 将 <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 命令并验证其是否具有以下值:

    • 已添加 application/json 类型的 Content-Type 标头值。
    • 已将函数密钥作为标头值 x-functions-key 传递。
    • 已使用 POST 请求。
    • 使用函数的 URL 传递了 Azure 函数。
  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 条目都具有 ID、时间戳和温度。

{
    "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 cmdlet 的调用。 在该函数运行时,这些语句会在日志窗口中添加消息。

测试业务逻辑

我们将使用“开发人员”>“代码 + 测试”中的“测试/运行”功能来测试函数。

  1. 在“输入”选项卡中,将“正文”文本框的内容替换为以下代码,以创建示例请求。

    {
        "readings": [
            {
                "driveGearId": 1,
                "timestamp": 1534263995,
                "temperature": 23
            },
            {
                "driveGearId": 3,
                "timestamp": 1534264048,
                "temperature": 45
            },
            {
                "driveGearId": 18,
                "timestamp": 1534264050,
                "temperature": 55
            }
        ]
    }
    
  2. 选择“运行”。 “输出”选项卡显示 HTTP 响应代码和内容。 若要查看日志消息,请在窗格底部的浮出控件中打开“日志”选项卡(如果尚未打开)。 下面的图像显示的是输出窗格中的响应以及“日志”窗格中的消息的示例。

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

    “输出”选项卡显示状态字段已正确添加到每个读数。

  3. 若要查看请求是否已记录到 Application Insights,请在左侧的“开发人员”菜单中选择“监视”。 此时将显示函数的“监视”窗格。

    窗格的“调用”选项卡显示每个函数调用的“调用跟踪”。 选择其中一项调用的“日期(UTC)”值,然后查看有关函数执行的详细信息。