练习 - 使用输出绑定写入数据

已完成

在上一练习中,我们实施了一个在 Azure Cosmos DB 数据库中查找书签的方案。 我们配置了一个输入绑定,用于从书签集合中读取数据。 但,我们还可以执行更多操作。 让我们扩展此方案,将写入包括进来。 请考虑以下流程图:

Decision flow diagram illustrating the process of adding a bookmark in Azure Cosmos DB back-end and returning a response.

在该场景中,我们会接收向集合添加书签的请求。 这些请求传入所需的密钥(或 ID)以及书签 URL。 正如流程图所示,如果密钥已经存在于后端,我们会以错误进行响应。

如果找不到传递给我们的密钥,我们将向数据库添加新书签。 这样就可以了,不过还可以继续操作。

注意到流程图中的另一步骤了吗? 到目前为止,我们并没有对接收的数据进行太多的处理。 我们将接收的内容移到一个数据库中。 但在实际解决方案中,我们可能会以某种方式处理数据。 我们可以在同一函数中完成所有处理,但在此练习中,我们会演示一个将其他处理卸载到另一业务逻辑组件或片段的模式。

在我们的书签场景中,哪些好的示例展示了卸载操作? 嗯,如果我们将新书签发送到 QR 代码生成服务,会出现什么情况? 此服务反过来会为 URL 生成 QR 码,将图像存储在 Blob 存储中,然后将 QR 图像的地址添加到“书签”集合的条目中。 通过调用服务来生成 QR 图很费时间。 因此,与其苦苦等待结果,不如将此任务交给一个函数,让该函数以异步方式完成此任务。

Azure Functions 支持多种集成源的输入绑定,同样,它也有一系列用于输出绑定的模板,可以很轻松地将数据写入数据源。 输出绑定也在 function.json 文件中配置。 在此练习中可以看到,我们可以对函数进行配置,使之适用于多个数据源和服务。

重要

本练习基于沙盒资源以及在先前单元中创建的资源;特别是 Azure Cosmos DB 数据库、书签和输入绑定。 如果尚未完成先前单元中的练习,则将无法完成本练习。

创建 HTTP 触发的函数

  1. Azure 门户中,通过在 HttpTrigger2 函数页面顶部的痕迹导航路径中选择函数应用的名称,转到创建的该函数应用。

  2. “概述”页上的“函数”选项卡中应具有创建的 HTTP 触发器函数。

  3. 在“函数”选项卡上选择“创建”。此时会显示“创建函数”窗格。

  4. 在“选择模板”部分下,依次选择“HTTP 触发器”和“创建”。 此时将显示 HttpTrigger3 函数的“概述”窗格。

添加 Azure Cosmos DB 输入绑定

接下来添加另一个 Azure Cosmos DB 输入绑定。

  1. 在“HttpTrigger3”函数菜单中,选择“集成”。 此时将显示“集成”窗格。

  2. 在“输入”框中,选择“添加输入”。 此时,“创建输入”窗格显示。

  3. 在“绑定类型”下拉列表中,选择“Azure Cosmos DB”。

  4. “Cosmos DB 帐户连接”设置应预先填充你在上一个练习中创建的连接

    如果连接未列出,请按以下步骤操作来新建连接。

    1. 在“Azure Cosmos DB 详细信息”部分中,选择“Cosmos DB 帐户连接”设置下的“新建”链接。

    2. 出现“新建 Cosmos DB 连接”对话框时,选择“确定”创建连接。 新建一个 Cosmos DB 帐户连接。

  5. 为此窗格中的另一个设置输入以下值。 要详细了解某个设置的用途,可随时选择其右侧的信息图标。

    设置 说明
    文档参数名称 bookmark 代码中用来标识此绑定的名称。
    数据库名称 func-io-learn-db 要使用的数据库。 该值为我们之前在本课中设置的数据库名称。
    集合名称 Bookmarks 从中读取数据的集合的名称。 我们之前在课程中定义了此设置。
    文档 ID {id} 添加 {id} 以使用正确的绑定表达式并接受在查询字符串中传递的参数。
    分区键 {id} 同样,添加 {id} 以使用正确的绑定表达式并接受在查询字符串中传递的参数。
    SQL 查询(可选) 留空 我们根据 ID 一次仅检索一个项目。 因此在此实例中,与使用 SQL 查询相比,通过“文档设置”进行筛选效果更好。 我们可以创建一个 SQL 查询来仅返回一个条目 (SELECT * from b where b.ID = /id)。 该查询的确会返回一个项目,但该项目是在项目集合中返回的。 我们的代码必须操作一个集合,这没有必要。 当希望获取多个文档时,请使用 SQL 查询方法。

    与在上一练习中创建的输入绑定一样,我们想要查找具有特定 ID 的书签,所以将函数在查询字符串中接收的“文档 ID”关联到绑定(称为绑定表达式)。 函数触发器是 HTTP 请求,该请求使用查询字符串指定要查找的 ID。 绑定返回 0(未找到)或 1(找到)个文档。

  6. 若要保存此输入绑定配置,请选择“确定”。

现在有一个 Azure Cosmos DB 输入绑定。 现在可以添加输出绑定了,以便在集合中写入新条目。

添加 Azure Cosmos DB 输出绑定

  1. 在 HttpTrigger3 的“集成”窗格的“输出”框中,选择“添加输出”。 此时,“创建输出”窗格显示。

  2. 在“绑定类型”下,从下拉列表中选择“Azure Cosmos DB”。

  3. “Cosmos DB 帐户连接”设置应预先填充你之前创建的连接。 如果未填充,请展开下拉列表并选择为 HttpTrigger3 输入绑定定义的连接。

  4. 为输出绑定的其余设置输入以下值。

    设置 说明
    文档参数名称 newbookmark 代码中用来标识此绑定的名称。 此参数用于写入新的书签项。
    数据库名称 func-io-learn-db 要使用的数据库。 该值为我们之前在本课中设置的数据库名称。
    集合名称 Bookmarks 从中读取数据的集合的名称。 此值是我们在本课前面定义的容器名称。
    分区键 /id 添加之前在创建书签 Azure Cosmos DB 容器时定义的分区键。 此处输入的密钥(输入绑定配置 <key> 中指定的)必须与容器中的密钥匹配。
  5. 若要保存此输出绑定配置,请选择“确定”。

现在我们有一个从集合中读取的绑定,以及一个写入它的绑定。

添加 Azure 队列存储输出绑定

Azure 队列存储是一项可存储消息的服务,用户可以从世界各地的任何位置访问这些消息。 一条消息的大小可达到 64 KB,一个队列中可以包含数百万条消息,直至达到定义所在存储帐户的总容量。 下图概要显示了如何在方案中使用队列。

Illustration showing a storage queue with a function pushing and another function popping messages.

在本例中,可以看到名为 add-bookmark 的函数将消息添加到队列,另一个名为 gen-qr-code 的函数将从同一队列弹出消息并处理请求。 由于是从“add-bookmark”向队列写入或推送消息,因此我们会向解决方案添加新的输出绑定

接下来通过门户创建绑定。

  1. 在函数的“集成”窗格上,选择“输出”框中的“添加输出”。 此时,“创建输出”窗格显示。

  2. 在“绑定类型”下拉列表中,选择“Azure 队列存储”。

    如果出现一条消息,提示你安装 Microsoft.Azure.WebJobs.Extensions.Storage 扩展,请选择“安装”并等待其完成。

接下来设置存储帐户连接,我们在其中托管了队列。

  1. 在“存储帐户连接”下,选择“新建”。 此时,“新建存储帐户连接”对话框显示。

  2. 在开始本模块时,创建函数应用会同时自动创建存储帐户。 从下拉列表中选择它,然后选择“确定”。

    “存储帐户连接”设置会填充连接的名称。

尽管可以保持默认值,但不妨更改某些设置来赋予其余属性更多含义。

  1. 通过将以下旧值替换为新值来完成“创建输出”窗格中的设置:

    设置 旧值 新值 说明
    消息参数名称 outputQueueItem newmessage 在代码中使用的绑定属性。
    队列名称 outqueue bookmarks-post-process 向其中放置书签的队列名称,以便另一函数可以进一步处理它们。
  2. 选择“确定”,保存 Azure 队列存储的输出配置。

更新函数实现

现在,我们设置了所有绑定。 可以在函数中使用它们了。

  1. 若要在代码编辑器中打开 index.js 文件,请选择函数 HttpTrigger3。

  2. 在菜单的“开发人员”下,选择“代码 + 测试”。 此时,函数的“代码和测试”窗格显示。

  3. 将 index.js 文件中的所有代码都替换为以下代码片段中的代码,然后选择命令栏中的“保存”。

    module.exports = function (context, req) {
    
        var bookmark = context.bindings.bookmark;
        if(bookmark){
                context.res = {
                status: 422,
                body : "Bookmark already exists.",
                headers: {
                'Content-Type': 'application/json'
                }
            };
        }
        else {
            
            // Create a JSON string of our bookmark.
            var bookmarkString = JSON.stringify({ 
                id: req.body.id,
                url: req.body.url
            });
    
            // Write this bookmark to our database.
            context.bindings.newbookmark = bookmarkString;
    
            // Push this bookmark onto our queue for further processing.
            context.bindings.newmessage = bookmarkString;
    
            // Tell the user all is well.
            context.res = {
                status: 200,
                body : "bookmark added!",
                headers: {
                'Content-Type': 'application/json'
                }
            };
        }
        context.done();
    };
    

接下来详细讲解此代码的功能:

  • 此函数会更改数据,因此 HTTP 请求需要是 POST,并且书签数据需要是请求正文的一部分。
  • Azure Cosmos DB 输入绑定会尝试使用我们收到的 id 来检索文档或书签。 如果它找到条目,则会设置 bookmark 对象。 if(bookmark) 条件会检查是否找到了条目。
  • 添加到数据库的操作很简单,只需将 context.bindings.newbookmark 绑定参数设置为已经作为 JSON 字符串创建的新书签条目即可。
  • 将消息发布到队列很简单,只需设置 context.bindings.newmessage 参数即可。

备注

你唯一执行的任务是创建队列绑定。 从未显式创建队列。 你会见识到绑定的强大功能! 根据以下通知声明,如果队列不存在,则会自动创建队列。

Screenshot showing message that the queue will be auto-created.

这部分的内容到此为止。 下一部分介绍如何运行我们在这一部分完成的工作内容。

  1. 若要在代码编辑器中打开 run.ps1 文件,请从窗格顶部的痕迹导航中选择 HttpTrigger3 函数。

  2. 在“函数”菜单的“开发人员”下,选择“代码 + 测试”。 此时将显示 HttpTrigger3 函数的“代码 + 测试”窗格,其中显示了 run.ps1 的默认内容。

  3. 请将文件中的内容替换为以下代码。

    using namespace System.Net
    
    param($Request, $bookmark, $TriggerMetadata)
    
    if ($bookmark) {
        $status = 422
        $body = "Bookmark already exists."
    }
    else {
        $newBookmark = @{ id = $Request.Body.id; url = $Request.Body.url }
    
        Push-OutputBinding -Name newbookmark -Value $newBookmark
    
        Push-OutputBinding -Name newmessage -Value $newBookmark
    
        $status = [HttpStatusCode]::OK
        $body = "bookmark added!"
    }
    
    Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
        StatusCode = $status
        Body = $body
        ContentType = "application/json"
    })
    
  4. 在命令栏中,选择“保存”。 连接已建立,一个日志文件会话随即打开。

接下来详细讲解此代码的功能:

  • 此函数会更改数据,因此 HTTP 请求需要是 POST,并且书签数据需要是请求正文的一部分。
  • Azure Cosmos DB 输入绑定会尝试使用请求中的 id 来检索文档或书签。 如果它找到条目,则会设置 bookmark 对象。 if ($bookmark) 条件会检查是否找到了条目。
  • 添加到数据库与使用 Cosmos DB 输出绑定的名称 (newbookmark) 和 $newBookmark 对象的值调用 Push-OutputBinding 一样简单。
  • 将消息发布到队列与使用队列输出绑定的名称 (newmessage) 和 $newBookmark 对象的值调用 Push-OutputBinding 一样简单。

备注

你唯一执行的任务是创建队列绑定。 从未显式创建队列。 你会见识到绑定的强大功能! 根据以下通知声明,如果队列不存在,则会自动创建队列。

Screenshot showing UI tool tip that the queue will be auto-created.

这部分的内容到此为止。 下一部分介绍如何运行我们在这一部分完成的工作内容。

试试看

我们有多个输出绑定,因此测试工作变得有点复杂。 在前面的单元中,我们只需发送 HTTP 请求和查询字符串进行测试,而这一次我们希望执行 HTTP Post 操作。 我们还需检查消息是否已让其进入队列中。

  1. 在 HttpTrigger3 函数的“代码 + 测试”窗格的命令栏中,选择“测试/运行”。 此时显示打开了“输入”选项卡的新窗格,如下图所示:

    Screenshot showing the test/run pane.

  2. 在“HTTP 方法”下拉列表中,验证“POST”。

  3. 将请求正文的内容替换为以下 JSON 对象:

    {
        "id": "docs",
        "url": "https://learn.microsoft.com/azure"
    }
    
  4. 选择“运行”。

  5. 编程进度在“日志”窗格中显示。 完成后,验证“HTTP 响应内容”设置中的“输出”选项卡是否显示“书签已存在。”。

    Screenshot of output tab showing bookmark already exists response.

    你在练习 - 读取包含输入绑定的数据中添加了书签项。 该响应确认 var bookmark = context.bindings.bookmark JavaScript 工作正常,并且 PowerShell 代码正在建立相同的连接。

  6. 接下来将第二个书签张贴到数据库。 选择“输入”选项卡。

  7. 将请求正文的内容替换为以下 JSON 对象:

    {
        "id": "github",
        "url": "https://www.github.com"
    }
    
  8. 选择“运行”。

  9. 验证“HTTP 响应内容”中的“输出”选项卡是否显示“已添加书签!”,如以下屏幕截图所示。

    Screenshot of output tab showing bookmark added response.

祝贺你! 函数按设计正常运行! 但添加到代码中的队列操作呢? 嗯,让我们看看是否有内容写入到队列中。

验证消息是否已写入队列中

Azure 队列存储队列托管在存储帐户中。 你在创建输出绑定时配置了存储帐户。

  1. 在 Azure 门户的全局搜索栏中,输入“存储帐户”,然后在结果列表中,选择“存储帐户”。 此时会显示“存储帐户”窗格。

    Screenshot showing search results for Storage Account search.

  2. 选择用于配置 newmessage 输出绑定的存储帐户。

  3. 在“存储帐户”菜单中的“数据存储”下,选择“队列”以列出此存储帐户托管的队列。 验证是否列出“bookmarks-post-process”队列,如以下屏幕截图所示。

    Screenshot showing queues hosted by this storage account.

  4. 选择 bookmarks-post-process,列出队列中的消息。 如果一切按计划进行,则队列中包含你向数据库添加书签时发布的消息。 该消息应如下所示。

    Screenshot of message queue with two messages.

    在此示例中,消息具有唯一 ID,且“消息文本”列显示 JSON 格式的书签。 你尝试添加的 Azure docs 书签没有消息,因为它已存在于数据库中。

  5. 可以进一步测试此函数,方法是在测试窗格中使用新的 ID/URL 集更改请求正文,然后运行此函数。 观察此队列,会看到有更多消息到来。 也可查看数据库,验证是否添加了新条目。

在此练习中,我们扩展了对绑定的认识,了解了输出绑定以及如何将数据写入到 Azure Cosmos DB 中。 我们添加了一个输出绑定以将消息发布到 Azure 队列。 此示例展示了绑定的实际功能,它可以对传入源中的数据整形并将其移到各种目标。 我们没有编写任何数据库代码,也无需自行管理连接字符串。 我们只是以声明方式配置了绑定,让平台负责确保连接的安全、缩放函数和缩放连接。