练习 - 使用输入绑定来读取数据

已完成

假设你希望创建一个书签查找服务。 服务最初是只读的。 如果用户希望查找某个条目,他们需发送包含该条目 ID 的请求,然后函数将返回 URL。 以下流程图说明了该逻辑流程。

流程图显示了在 Azure Cosmos DB 中查找书签并返回响应的逻辑流程。

用户发送带有文本的请求时,查找书签函数会尝试在数据库中查找包含以文本为密钥或 ID 的书签的条目。 系统将返回指明是否找到该条目的结果。

当 Azure 函数收到包含书签 ID 的请求时,它首先检查请求是否有效。 如果无效,则生成错误响应。 如果请求有效,该函数会检查书签 ID 是否位于 Azure Cosmos DB 数据库。 如果此条目不存在,则生成错误响应。 如果找到书签 ID,则生成成功响应。

你需要将数据存储到某处。 在之前的流程图中,数据存储是一个 Azure Cosmos DB 实例。 但是,如何从函数连接到数据库并读取数据? 在函数的世界中,你为该项工作配置了一个“输入绑定”。 通过 Azure 门户配置输入绑定非常简单。 你稍后就会看到,不必编写代码或打开存储连接。 Azure Functions 运行时和绑定可为你处理这些任务。

创建 Azure Cosmos DB 帐户

注意

此练习不是关于 Azure Cosmos DB 的教程。 如果希望学习更多内容,请参阅本模块末尾关于 Azure Cosmos DB 的完整学习路径。

创建数据库帐户

数据库帐户是用于管理一个或多个数据库的容器。 必须先创建数据库帐户,然后才能创建数据库。

  1. Azure 门户资源菜单上或在“主页”中,选择“创建资源”。 此时会显示“创建资源”窗格。

  2. 在“创建资源”菜单中,选择“数据库”,然后搜索并选择 Azure Cosmos DB。 此时会显示“哪个 API 最适合你的工作负载?”窗格。

  3. 在“Azure Cosmos DB for NoSQL”选项中,选择“创建”,确保可以创建 Cosmos DB 触发器和输入/输出绑定。 此时会显示“创建 Azure Cosmos DB 帐户 - Azure Cosmos DB for NoSQL”窗格。

  4. 在“基本信息”选项卡上,为每个设置输入以下值。

    设置 说明
    项目详细信息
    订阅 Concierge 订阅 使用沙盒中的资源的 Azure 订阅。
    资源组 从下拉列表中,选择 [沙盒资源组名称] 沙盒的资源组。
    实例详细信息
    帐户名 globally unique name 为 Azure Cosmos DB 帐户输入唯一但易识别的名称;在提供的名称之后追加 documents.azure.com

    3 - 50 lowercase characters, numbers, or hyphens (-)
    位置 region 选择离你最近的区域。
  5. 接受其余设置的默认值,然后选择“查看 + 创建”以验证输入。 此时,“验证成功”通知显示。

  6. 选择“创建”以预配并部署数据库帐户。

  7. 部署可能需要一段时间。 在继续操作之前,请等待通知中心发出“已成功部署”消息。

    指出数据库帐户部署已完成的通知的屏幕截图。

  8. 选择“转到资源”,以在门户中转到数据库帐户。 此时,Azure Cosmos DB 帐户的“快速入门”窗格显示。

接下来,我们将添加一个容器,然后项 Azure Cosmos DB 帐户添加一个数据库。

添加容器

在 Azure Cosmos DB 中,容器用于存储各种用户生成的实体(又称为“项”)。 我们将创建一个称为 Bookmarks 的容器。

接下来,我们要使用数据资源管理器工具来创建数据库和容器。

  1. 在 Azure Cosmos DB 帐户菜单中,选择“数据资源管理器”。 此时显示 Cosmos DB 帐户的“数据资源管理器”窗格。

  2. 选中“新建容器”框。 此时,“新建容器”窗格显示。 可能需要滚动才能看到。

  3. 为每个设置输入以下值。

    设置 描述
    数据库 ID 选择“新建”,然后输入“func-io-learn-db”作为数据库 id 数据库名称的长度可以为 1 到 255 个字符,并且不能包含 /, \\, #, ? 或尾随空格。
    可输入任何内容,但在本模块中我们使用 func-io-learn-db。
    数据库每秒最大 RU 数 4000 接受默认吞吐量为每秒 4000 个请求单位 (RU/s)。 若要减少延迟,可稍后扩展性能。
    容器 ID 书签 容器 ID 与数据库名称的字符要求相同。 我们在本模块中使用“书签”。
    分区键 /id 分区键指定 Azure Cosmos DB 集合中的文档在多个逻辑数据分区中的分布方式。 为方便起见,我们在这里使用“分区键”设置,因为不考虑此模块中的数据库性能。 若要深入了解 Azure Cosmos DB 分区键策略,请浏览 Microsoft Learn Azure Cosmos DB 模块。

    接受所有其他设置的默认值。

  4. 滚动到窗格底部,并选择“确定”。 等待数据库和容器构建完毕,可能需要几分钟时间。

    完成后,数据资源管理器在 NOSQL API 下的“数据”中显示 func-io-learn-db

  5. 选中 func-io-learn-db 将其展开。 请注意,func-io-learn-db 数据库包含多个子成员,包括“缩放”和“书签”。

  6. 展开书签容器。 请注意,多个子成员已经预填充它。

在下一个任务中,你将向 Bookmarks 容器添加一些数据(又称为项)。

添加测试数据

建议将数据添加到“书签”容器。 使用数据资源管理器来存储每个项的 URL 和 ID。

  1. 展开“func-io-learn-db”数据库和“书签”容器,然后选择“项”。 此时将显示“项”选项卡。

  2. 在命令栏上,选择“新建项”。

  3. 将新项的默认代码替换为以下 JSON 代码。

    {
        "id": "docs",
        "url": "https://learn.microsoft.com/azure"
    }
    
  4. 在命令栏中,选择“保存”。

    请注意,除了我们添加的两行属性,还会显示其他属性。 这些属性都以下划线 (_rid, _self, _etag, _attachments, _ts) 开头。 下表所述的这些属性由系统生成,可帮助管理添加到容器中的项。

    properties 说明
    _rid 资源 ID 是唯一标识符,也是按资源模型上的资源堆栈分层的。 该 ID 在内部用于项目资源的放置和导航。
    _self 资源的唯一可寻址 URI。
    _etag 乐观并发控制所必需的。
    _attachments 附件资源的可寻址路径。
    _ts 此资源的上次更新时间戳。
  5. 接下来再向“书签”容器添加一些项。 在命令栏上,选择“新建项”。 使用以下内容再创建 4 个项目。 通过选择“新建项”,然后在复制并粘贴每个新项后选择“保存”来添加项。 请注意如何将每个项添加到项列表。

    {
        "id": "portal",
        "url": "https://portal.azure.com"
    }
    
    {
        "id": "learn",
        "url": "https://learn.microsoft.com/training"
    }
    
    {
        "id": "marketplace",
        "url": "https://azuremarketplace.microsoft.com/marketplace/apps"
    }
    
    {
        "id": "blog",
        "url": "https://azure.microsoft.com/blog"
    }
    
  6. 输入书签数据后,你的容器应如下图所示。

    SQL API 数据的屏幕截图,其中显示了 func-io-learn-db 的书签容器中的项集合。

“书签”容器有五个项。 在这种情况下,如果请求到达且它带有“id=docs”内容,则将在 Bookmarks 容器中查找该 ID 并返回 URL https://learn.microsoft.com/azure。 接下来创建一个 Azure 函数,用以在“书签”容器中查找值。

创建函数

  1. 转到上一单元中创建的函数应用。 在资源菜单中,选择“主页”,在“最新资源”部分,应显示函数应用(“类型”为“函数应用”)。 选择函数应用。 此时将显示“函数应用”窗格。

  2. “概述”页上的“函数”选项卡中应具有一个函数 HttpTrigger1

  3. 接下来创建另一个函数。 在“函数”选项卡上选择“创建”。此时会显示“创建函数”窗格,其中列出了支持的触发器的模板

  4. 在“选择模板”部分中,依次选择“HTTP 触发器”和“下一步”

  5. 接受所有默认设置,然后选择“创建”来创建函数。

    此时会显示 HttpTrigger2 函数的“概述”窗格。

验证函数

到目前为止,可以通过测试新函数来验证我们的进度。

  1. 在命令栏中,选择“获取函数 URL”。 此时将显示“获取函数 URL”对话框。

  2. 从下拉列表中选择“默认(函数键)”,然后选择“复制到剪贴板”图标并选择“确定”

  3. 将复制的函数 URL 粘贴到新浏览器标签页的地址栏。将查询字符串值 &name=<your name> 追加到 URL 的末尾,并将 <your name> 替换为你的姓名,然后按 Enter。 Azure 函数应在浏览器中返回个性化的响应。

现在,我们有了正常工作的 skeletal 函数,接下来我们将重点关注如何从 Azure Cosmos DB 中读取数据,在我们的场景中是从“书签”容器中读取。

添加 Azure Cosmos DB 输入绑定

若要从数据库读取数据,需要定义输入绑定。 如你所见,只需几个步骤便可配置可以与数据库进行通信的绑定。

  1. 在 Azure 门户中,从顶部的“HttpTrigger2”函数菜单中选择“集成”。 此时,函数的“集成”窗格显示。

    你使用的模板已经创建了一个带有 HTTP 输出绑定的 HTTP 触发器请求。 接下来添加 Azure Cosmos DB 输入绑定。

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

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

  4. 在“Azure Cosmos DB 详细信息”部分中,选择“Cosmos DB 帐户连接”设置下的“新建”链接。 此时,“新建 Cosmos DB 连接”对话框显示。

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

  5. 默认情况下,Azure 会识别之前创建的 Azure Cosmos DB 帐户。 选择“确定”以建立与数据库的连接。 到数据库帐户的新连接已配置并显示在“Cosmos DB 帐户连接”字段中。

    我们希望查找具有特定 ID 的书签,因此,接下来让我们将在查询字符串中收到的 ID 关联到绑定。

  6. 接下来,完成“创建输入”窗格中的设置 。 为每个设置输入以下值。 要详细了解每个设置的用途,请选择该字段中的信息图标。

    设置 说明
    文档参数名称 bookmark 代码中用来标识此绑定的名称。
    数据库名称 func-io-learn-db 要使用的数据库。 该值为我们设置的数据库名称。
    集合名称 Bookmarks 从中读取数据的集合。 该设置已定义。
    文档 ID id 添加在创建书签 Azure Cosmos DB 容器时定义的文档 ID。
    分区键 /id 添加在创建书签 Azure Cosmos DB 集合时定义的分区键。 此处输入的键(指定为输入的绑定格式 <key>)必须与集合中的键匹配。
    SQL 查询(可选) 留空 你将基于 ID 一次仅检索一个文档。 因此,在此实例中,使用文档 ID 设置进行筛选比使用 SQL 查询要好。 可以创建一个 SQL 查询来仅返回一个条目 (SELECT * from b where b.ID = id)。 该查询实际上将返回一个文档,但它会在文档集合中返回该文档。 你的代码必须操作一个集合,而这是没有必要的。 当希望获取多个文档时,请使用 SQL 查询方法。

    为阐明使用这些设置的原因,我们需要查找具有特定 ID 的书签,所以将函数在查询字符串中接收的“文档 ID”关联到输入绑定。 该语法称为“绑定表达式”。 此函数由一个 HTTP 请求触发,该请求使用查询字符串指定要查找的 ID。 由于 ID 在我们的集合中是唯一的,因此该绑定将返回 0(未找到)或 1(已找到)个文档。

  7. 若要保存此输入绑定配置,请选择“添加”

更新函数实现

定义绑定后,可以在函数中使用它。 需进行两项更改以实现创建的绑定:

  • 修改函数的特定于语言的实现代码。 需要确定能否在数据库中找到与传递给函数的 ID 相匹配的文档。

  • 修改函数的 JSON 实现代码,以接受通过查询字符串传递的参数。

修改函数的 JavaScript 实现代码

  1. 在 HttpTrigger2 函数的“函数”菜单中,选择“代码 + 测试”。 此时将显示 HttpTrigger2 函数的“代码 + 测试”窗格。

  2. 将 index.js 文件中的所有代码替换为以下代码。

    module.exports = function (context, req) {
    
        var bookmark = context.bindings.bookmark
    
        if(bookmark){
            context.res = {
            body: { "url": bookmark.url },
            headers: {
                'Content-Type': 'application/json'
            }
            };
        }
        else {
            context.res = {
                status: 404,
                body : "No bookmarks found",
                headers: {
                'Content-Type': 'application/json'
                }
            };
        }
    
        context.done();
    };
    
  3. 在命令栏中,选择“保存”。 在“日志”窗格顶部中央的下拉列表中,选择“文件系统日志”(默认显示“App Insights”日志)。 此时将显示“日志”窗格,其中显示了你已 Connected!

让我们来看一下该代码执行的操作。

  • 传入的 HTTP 请求会触发该函数,并将 id 查询参数传递到 Azure Cosmos DB 输入绑定。

  • 如果数据库找到与此 ID 匹配的文档,则将 bookmark 参数设置为找到的文档。

    在该示例中,代码构建了一个响应,其中包含在数据库的响应文档中发现的 URL 值。

  • 如果未找到与此键匹配的文档,则请求会以有效负载和状态代码进行响应来将坏消息告诉用户。

修改函数的 JSON 实现代码

  1. <functionapp> \ HttpTrigger2 \ 路径的下拉列表中选择“function.json”

  2. 将 function.js 文件中的所有代码替换为以下代码。 请务必将 your-database 替换为 Azure Cosmos DB 帐户的名称。

    {
      "bindings": [
        {
          "authLevel": "function",
          "type": "httpTrigger",
          "direction": "in",
          "name": "req",
          "methods": [
            "get",
            "post"
          ]
        },
        {
          "type": "http",
          "direction": "out",
          "name": "res"
        },
        {
          "name": "bookmark",
          "direction": "in",
          "type": "cosmosDB",
          "partitionKey": "{id}",
          "databaseName": "func-io-learn-db",
          "containerName": "Bookmarks",
          "connection": "your-database_DOCUMENTDB",
          "id": "{id}",
        }
      ]
    }
    
  3. 在命令栏中,选择“保存”。

修改函数的 PowerShell 实现代码

  1. 在 HttpTrigger2 函数的“函数”菜单中,选择“代码 + 测试”。 此时将显示 HttpTrigger2 函数的“代码 + 测试”窗格,其中显示了 run.ps1 文件。

  2. run.ps1 文件中的所有代码替换为以下代码。

    using namespace System.Net
    
    param($Request, $bookmark, $TriggerMetadata)
    
    if ($bookmark) {
        $status = [HttpStatusCode]::OK
        $body = @{ url = $bookmark.url }
    }
    else {
        $status = [HttpStatusCode]::NotFound
        $body = "No bookmarks found"
    }
    
    Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
        StatusCode = $status
        Body = $body
    })
    
  3. 在命令栏中,选择“保存”。 在“日志”窗格顶部中央的下拉列表中,选择“文件系统日志”(默认显示“App Insights”日志)。 此时将显示“日志”窗格,其中显示了你已 Connected!

让我们来看一下该代码执行的操作。

  • 传入的 HTTP 请求会触发该函数,并将 id 查询参数传递到 Azure Cosmos DB 输入绑定。

  • 如果数据库找到与此 ID 匹配的文档,则将 bookmark 参数设置为找到的文档。

    在该示例中,代码构建了一个响应,其中包含在数据库的响应文档中发现的 URL 值。

  • 如果未找到与此键匹配的文档,则请求会以有效负载和状态代码进行响应来将坏消息告诉用户。

修改函数的 JSON 实现代码

  1. <functionapp> \ HttpTrigger2 \ 路径的下拉列表中选择“function.json”

  2. 修改 idpartitionKey 的值,以便它们接受 {id} 的参数。 function.json 代码应如下例所示,其中 your-database 替换为 Cosmos DB 数据库的名称。

    {
      "bindings": [
        {
          "authLevel": "function",
          "type": "httpTrigger",
          "direction": "in",
          "name": "Request",
          "methods": [
            "get",
            "post"
          ]
        },
        {
          "type": "http",
          "direction": "out",
          "name": "Response"
        },
        {
          "type": "cosmosDB",
          "name": "bookmark",
          "databaseName": "func-io-learn-db",
          "containerName": "Bookmarks",
          "connection": "your-database_DOCUMENTDB",
          "direction": "in",
          "id": "{id}",
          "partitionKey": "{id}"
        }
      ]
    }
    
  3. 在命令栏中,选择“保存”。

试试看

  1. 此时应已显示 HttpTrigger2 函数的“代码 + 测试”窗格。

  2. 在命令栏中,选择“获取函数 URL”。 此时,“获取函数 URL”对话框显示。

  3. 在“键”下拉列表中,选择“函数键”下的“默认”,然后选择 URL 末尾的“复制到剪贴板”图标。

  4. 将复制的函数密钥粘贴到新浏览器标签页的地址栏,然后在 URL 的末尾添加查询字符串值 &id=docs。 生成的 URL 应与下面的示例类似:

    https://example.azurewebsites.net/api/HttpTrigger2?code=AbCdEfGhIjKlMnOpQrStUvWxYz==&id=docs

  5. 若要运行请求,请按 Enter。 函数返回的响应应如下例所示。

    {
      "url": "https://learn.microsoft.com/azure"
    }
    
  6. &id=docs 替换为 &id=missing,按 Enter,然后观察响应。 我们定义了五个书签,并针对请求的书签不存在的情况创建了一个有意义的错误响应。

在本单元中,你手动创建了你的第一个输入绑定来从 Azure Cosmos DB 数据库中读取数据。 归功于绑定,你只编写了很少的代码来搜索数据库以及读取数据。 你的大部分工作是以声明的方式配置绑定,平台完成了其余工作。

在下一单元中,你将通过 Azure Cosmos DB 输出绑定向书签集合添加更多数据。