发布于 2026-01-06 0 阅读
0

学习使用 JavaScript、CosmosDB 和 Slack 触发无服务器数据库

学习使用 JavaScript、CosmosDB 和 Slack 触发无服务器数据库

本文是#25DaysOfServerless活动的一部分。整个十二月,微软云技术倡导者每天都会发布新的挑战。了解更多关于 Microsoft Azure 如何助力您实现无服务器功能的信息

有什么想法或解决方案吗?

愿望大师2000
又到了一年一度的节日季。孩子们开始许愿,希望在圣诞袜里收到一份惊喜礼物。
为了让圣诞老人能把礼物送到每个孩子手中,他希望孩子们能给他写信。
他当然知道我们生活在2019年,互联网无处不在。收到数百万封手写信件的时代已经一去不复返了。他还希望每次收到新的愿望时,精灵们都能收到通知。

圣诞老人需要以下物品:

  • 网页应该将请求发送到函数端点,以便存储愿望及其所有元数据。
  • 用于存储愿望的函数端点,此端点应接收孩子的愿望并将其存储在 CosmosDB 数据库中。
  • 这是一个由 CosmosDB 触发的函数端点,该端点应该对数据库中插入的每个新愿望做出反应,并向精灵们管理的 Slack 频道写入一条消息。
  • 我们建了一个精灵专用的Slack群组,每次数据库里有了新内容,我们都想让精灵们知道,这样他们就不会偷懒了:)

让我们绘制出这个系统的架构图,以便对整个情况有一个宏观的了解:

参考

网页

网页应该支持收集发布愿望所需的数据。那么,愿望都包含哪些内容呢?

  • 愿望,愿望本身,这应该是一个更长的文字描述。
  • 来自,这应该是写祝福的人的姓名,最好是姓名+地址。

好的,那么我们需要什么来构建这个网页呢?很容易想到我们需要一个单页应用(SPA)框架。为了证明并非如此,我将使用原生 JavaScript 来构建它,也就是不使用任何框架。为此,我需要以下文件:

-| /webpage
---| index.html
---| app.js
---| app.css

请确保您拥有类似这样的工具http-server,以便您可以轻松地在本地测试此网页。

index.html

这部分应该包含网页的标记。也就是说,需要包含用于接收用户请求的输入字段,以及将内容提交到目标端点的方式。

请将内容更改为以下内容:

<!--  index.html -->

<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="app.css">
  </head>
  <body>
    <div class="page">
      <h2>Make wish</h2>
      <div class="item">
        <textarea rows="10" cols="70" placeholder="I wish..." name="wish" id="wish"></textarea>
      </div>
      <div class="item">
        <input type="text" placeholder="From" name="from" id="from" />
      </div>
      <div class="item">
        <button id="sendButton">
          Send
        </button>
      </div>
    </div>
    <div class="item response" id="response">
    </div>>
    <script src="app.js"></script>
  </body>
</html>

app.js

这应该能够连接所有事件,并向指定端点执行所需的 Web 请求。请添加以下内容:

// app.js

const sendEl = document.getElementById('sendButton');
const wishEl = document.getElementById('wish');
const fromEl = document.getElementById('from');
const responseEl = document.getElementById('response');

const baseUrl = 'http://localhost:7000';

sendEl.addEventListener('click', sendWish)

async function sendWish() {
  console.log('send wish');
  const res = await fetch(`${baseUrl}/wish`, {
    method: 'POST',
    body: JSON.stringify({
      wish: wishEl.innerHTML,
      from: fromEl.innerHTML
    })
  })
  const json = await res.json();
  console.log('response', json);
  responseEl.innerHTML = json;
}

app.css

我们需要为它添加一些合适的样式。让我们添加以下 CSS 类:

.page {
  background: darkmagenta;
  color: white;
  display: flex;
  align-items: center;
  padding: 20px;
  flex-direction: column;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

.page .item {
  margin-top: 10px;
}

.page .item textarea {
  width: 100%;
}

.page .item button {
  font-size: 16px;
  border: solid 1px darkorange;
  padding: 5px 10px;
  color: white;
  background: orange;
}

.page .item .response {
  font-style: italic;
}

试试看

http-server -p 8008让我们通过启动并运行我们的应用程序来看一下http://localhost:8080

 用于存储愿望的函数端点

接下来,我们需要一个端点,供上述网页发送请求。我们可以将其构建为一个函数应用。请确保已安装以下软件:

  • 安装 Azure Functions Core 工具。请点击此处查看适用于您操作系统的安装说明

  • 安装 VS Code 扩展,查找名为“Azure Functions

准备好了吗?好的,我们走吧 :)

构建函数应用

这一步骤包括我们执行以下操作:

  • 配置 CosmosDB 数据库,我们需要一个数据库来存储我们的请求。
  • 搭建函数应用框架,这意味着创建函数应用、函数端点,并添加连接到我们刚刚创建的 CosmosDB 数据库所需的代码。

提供 CosmosDB 数据库

点击左上角的菜单,portal.azure.com然后选择出现的模板。+ Create a resourceAzure Cosmos DB

请填写相应字段:

资源创建完成后,我们需要进入该资源并选择菜单选项Data ExplorerNew Container如下所示:

您将被要求填写以下字段:

  • 数据库 ID,你可以随意命名,我选择命名为WishDB
  • 吞吐量,将其值设为 1000。
  • 容器 ID,也就是集合的名称。集合包含一个文档列表。每个文档都类似于表中的一行,表和集合本质上是相同的。给它起个名字。Wishes
  • 分区键,分区键指定 Azure Cosmos DB 集合中的文档如何在逻辑数据分区之间分布。这到底是什么意思呢?这意味着此数据库可以在云端扩展。我们告诉它如何扩展,以及如何使用分片技术来实现扩展。请提供该值。/id

搭建函数应用程序

让我们在 VS Code 中打开命令面板并输入Azure Functions: Create New Project

选择 JavaScript,当系统询问第一个函数时,为其命名Wish并确保它由 HTTP 触发。接下来,将Wish/index.js代码更改为以下内容:

function uuidv4() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0,
            v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

module.exports = async function (context, req) {
    context.log('Entering function');

    if (!req.body.wish || !req.body.from) {
        context.res = {
            status: 400,
            body: "Please pass wish,from"
        };
    }

    const {
        wish,
        from
    } = req.body;

    context.bindings.newWish = JSON.stringify({
        id: uuidv4(),
        wish,
        from
    })
    context.done();
};

该函数uuidv4()会生成一个唯一的 ID,这在数据库中非常有用。我们导出的主函数本身,只是从请求体中提取出 `<request_body>`wish和`<request_body>`,并将它们赋值给 `<request_body> `。最后,我们调用 `<request_body>` 。这就是将此内容插入CosmosDB 数据库所需的全部步骤。fromcontext.bindings.newWishcontext.done()

我们还没完全完成。我们还需要做两件事:

  • 连接到我们的数据库,我们通过local.settings.json使用连接字符串进行更新来实现这一点。
  • 安装 CosmosDB 所需的绑定,我们需要更新host.json以安装对 CosmosDB 的绑定支持。

连接到我们的数据库

CosmosDB我们需要在属性Values添加以下键local.settings.json。该属性的值应赋值为数据库的连接字符串信息,我们可以在portal.azure.com菜单选项Keys和字段中找到它PRIMARY CONNECTION STRING

接下来,我们需要更新Wish/function.json并添加一个绑定,该绑定指向我们的CosmosDB键,local.settings.json同时也指向数据库名称、集合以及我们可以引用的名称引用。我们需要将以下绑定条目添加到bindings数组中function.json

{
  "name": "newWish",
  "type": "cosmosDB",
  "databaseName": "WishDB",
  "collectionName": "Wishes",
  "createIfNotExists": true,
  "connectionStringSetting": "CosmosDB",
  "direction": "out"
}

如上所示,我们指出了上述所有内容,以便连接到我们的数据源。此外,我们还指出了newWish我们在 . 中引用的命名引用Wish/index.js

安装 CosmosDB 绑定

我们需要安装 CosmosDB 的绑定。这意味着我们需要一些库,以便我们的 JavaScript 代码能够与 CosmosDB 代码进行通信。打开host.json函数应用根目录下的文件,并添加以下内容:

{
  "version": "2.0",
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[1.*, 2.0.0)"
  }
}

下面这些值extensionBundle会强制 VS Code 在调试模式下安装所有需要的绑定。

在生产环境中,这样做可能有点过度。通常情况下,您只需要安装 CosmosDB 即可。一旦我找到只安装 CosmosDB 的方法,而不是像现在这样安装所有组件,我就会更新这篇教程。

CosmosDB 触发函数端点

该解决方案包含两部分:

  • 当数据库中出现新行时,就会触发一个函数端点。当数据库中发生新的更改(例如新增一行)时,我们的函数端点将被调用。
  • 通过与 Slack 集成,一旦我们的函数被调用,我们就能将刚刚在数据库中创建的数据获取出来,并将其发送到其他地方。这个其他地方就是 Slack。

函数端点

首先,我们将搭建函数终结点。我们可以使用 VS Code 中的 Azure 函数扩展,通过命令面板和相应选项轻松完成此操作Azure Function: Create function。给这个新函数命名NewWish,并确保它使用`<function_name>` 和 `<authorization>`JavaScript作为Anonymous授权(部署后,我们可以将其更改为 `<function_name>` 以提高安全性)。

NewWish/function.json

接下来,我们需要添加一个连接到 CosmosDB 数据库的外部function.json绑定。我们的NewWish目录应该包含以下内容:

{
  "bindings": [
    {
      "type": "cosmosDBTrigger",
      "name": "documents",
      "direction": "in",
      "connectionStringSetting": "CosmosDB",
      "databaseName": "WishDB",
      "collectionName": "Wishes",
      "createLeaseCollectionIfNotExists": "true"
    }
  ]
}

如您所见,我们赋予它以下值:

  • 类型,其值为cosmosDBTrigger,这将确保在向数据库添加新行时触发该函数。
  • 名称,这是我们在代码中将要使用的名称。
  • 方向必须正确in,因为数据是传入的,我们正在读取它。
  • connectionStringSetting,它指向一个名为 的内容CosmosDB,这是我们需要设置的键。local.settings.json
  • databaseName,这是我们在创建数据库时为其指定的名称。
  • collectionName,这是我们在创建它时赋予它的名称。

local.settings.json

如前所述,这需要一个名为 `ConnectionString` 的键CosmosDB,该键需要指向 Azure 门户中数据库资源的连接字符串。让我们从该local.setting.json文件开始:

"Values": {
    "AzureWebJobsStorage": "<should point to connection string for a storage account>",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "CosmosDB": "<should point to connection string for your CosmosDB database>"
  }

接下来,转到 Azure 门户中的资源,然后找到菜单选项Keys并复制其下的值PRIMARY CONNECTION STRING。至于存储帐户,我们暂时先不用管它,因为首次调试时系统会提示我们输入帐户。

NewWish/index.js

因为我们将使用该库node-fetch,所以首先在函数应用程序的根目录下运行以下命令:

npm install node-fetch

接下来,给index.js文件添加以下内容:

const fetch = require('node-fetch');

module.exports = async function (context, documents) {

  if (!!documents && documents.length > 0) {
      context.log('Document Id: ', documents[0].id);

      // call slack
      const [row] = documents;

      fetch(
        "<webhook URL at slack>",
        {
          method: "POST",
          body: JSON.stringify({
            text: `ID: ${row.id} FROM: ${row.from} WISH: ${row.wish}`
          }),
          headers: { "Content-Type": "application/json" }
        }
      );
  }
}

当数据库收到新行时,会调用上述代码。新行存储在参数中。然后,我们会调用 Slack API并将documents信息发布到 `<app_name>`、`<app_name>`和 ` <app_name>` 上。不过,我们缺少 WebHook URL,接下来需要解决这个问题。IdFromWish

Slack WebHook

我们需要以下条件才能与 Slack 通信。

  • 创建 Slack 工作区,请按照此指南创建工作区
  • 创建 Webhook
    • 创建一个 Slack 应用(如果你还没有的话)。
    • 在设置页面启用传入 Webhook 。
    • 点击“向工作区添加新的 webhook” 。
    • 选择应用要发布内容的渠道,然后点击“授权”。

然后你应该会看到类似这样的页面:

按下按钮后Copy,我们现在应该就能得到所需的 WebHook URL,并且可以更新我们的fetch调用了NewWish/index.js。不如我们来试一试吧?

测试一下

为了验证这一点,我们需要执行以下操作:

  • 要启动并运行该功能,我们通过选择来实现。Debug/Start Debugging
  • 要添加新行,我们访问 portal.azure.com,找到我们的资源,然后向数据库中添加一个新条目。
  • 查看 Slack 频道,我们的 Slack 频道现在应该包含端点NewWish发送到 Slack 的已发布消息。

启动并运行该功能

我们进行选择Debug/Start Debugging,结果应该如下所示:

添加新行

通常情况下,我们会使用 Web 应用程序将数据插入数据库。但在这里,我们将采用更简单的方法,直接在 Azure 中访问数据库资源,选择菜单选项Data Explorer并单击New Item。之后,我们为其指定以下值:

{
  "id": "some_id",
  "from": "Chris",
  "wish": "World peace"
}

然后点击Save

首先,程序应该会在我们的 FunctionApp 中触发断点/NewWish,如下所示:

我们取消了断点,然后转到我们的 Slack 频道。

成功了!我们的数据库插入操作触发了函数应用的调用,该应用随后将消息发布到了 Slack 上。这下那些小精灵们可要小心了 ;)

概括

这真是一项不小的工程,涉及很多环节。但仔细想想,每个环节其实都很容易搭建,而且我们在连接 CosmosDB 的过程中也得到了很多帮助,这使得整个项目最终得以顺利完成。

你想提交你对这个挑战的解决方案吗?


想提交你的解决方案吗?请在本地构建解决方案,然后提交一个 issue。如果你的解决方案不涉及代码,你可以录制一段简短的视频,并在 issue 描述中附上链接。请务必告诉我们你的解决方案是针对哪个挑战的。我们非常期待看到你的作品!你有任何意见或问题吗?请在下方评论区留言。


整个十二月,我们将举办为期 25 天的无服务器架构挑战赛,敬请期待!请持续关注 dev.to,我们将在此发布挑战和解决方案!立即注册Azure 免费帐户,为挑战做好准备!

文章来源:https://dev.to/azure/learn-serverless-database-trigger-in-javascript-cosmosdb-slack-fm1