原文地址:https://blog.cloudflare.com/building-a-serverless-slack-bot-using-cloudflare-workers/
原文标题:Building a serverless Slack bot using Cloudflare Workers
原文作者:Rita Kozlov
原文写于:2018/6/22 GMT+8 下午9:00:00
译者:驱蚊器喵#ΦωΦ
翻译水平有限,有不通顺的语句,请见谅。
译者注:
最近在研究 Cloudflare Workers,可能会搬运和翻译有关 Cloudflare Workers 的很多文章。
Slack app 可能很少人会用,但是既然能搭建 Slack Bot,能不能搭建别的呢?比如, Telegram Bot.
据 Alpha Vantage API 文档,API 免费版的频率限制为
up to 5 API requests per minute and 500 requests per day
每分钟最多 5 次,并且每天最多 500 次
感觉 500 次,连覆盖一天的每一分钟都不够,所以这个例子看看就好,slack bot 也没有 Telegram bot 方便易用,配置太多了。
注意:原文有些不完善,我根据目前的情况做了一些修改。
如果你不想看原理和废话,只想看代码和部署教程,可以直接跳转到译者注:部署教程。
我们的 Workers 平台 可用于许多有用的用途: A/B(多变量)测试,存储桶身份验证,合并来自多个 API 的响应,等等。但是,我们还可以在 “HTTP 中间件”之外使用 Workers:Worker 本身可以有效地成为 Web 应用程序。鉴于“聊天机器人”的兴起,我们还可以使用 Cloudflare Workers 构建 Slack 应用程序,并且无需服务器(嗯,至少不是需要您的服务器!)。
我们要构建什么
我们将构建一个 Slack 机器人(作为一个外部的 webhook)来获取最新的股价。
这个 Worker 也可以修改来从 GitHub 的 API 获取开启的 issues;用于发现下班后可以看什么电影; 以及任何可以使用 REST API 进行查询的工作。
然而,我们这次要做的是 “股票价格机器人”:
通过 Alpha Vantage API 来获取股票价格。
将最有价值的股票和他们的公开代码缓存下来,这样你就可以请求
/stocks MSFT
作为速记(译者注:MSFT 是 Microsoft 公司的上市代码)。利用 Cloudflare 的缓存来最大程度地减少每次调用 API 所需的时间,同时仍可提供最新的价格数据。
使用缓存,可以让你缩短所有调用 Worker 的响应时间。而且,尽可能减少对 API 的多余调用(以免你受到频率限制!)也是一种有礼貌的行为,所以,这是一举两得的好处。
准备工作
为了开始构建,您需要准备以下:
- 一个 Cloudflare 账号, 并启用 Workers 功能 (见备注)
- 一些基本的编程经验.
- 一个现有的 Slack 工作区. 如果你没有,请按照 Slack 的帮助指南进行操作。
注意:您可以在 Cloudflare 仪表板中的 “Workers” 应用程序启用 Workers 功能。
译者注:启用后,如果你没有域名,引导程序会为你分配一个 workers.dev 的子域名,用于 worker 的 webhook 使用,例如 subdomain.workers.dev,subdomain
是你自定义的子域名。
创建 Worker 程序
我们将首先启动运行 Worker,在 Slack 之外对其进行测试,然后再进行连接。我们的工人需要满足以下步骤:
- 处理来自 Slack 传入的 Webhook 请求(HTTP POST请求),包括对其进行身份验证,确认请求实际来自 Slack 。
- 从用户的消息( Webhook 内容)中解析请求的标识。
- 向 Alpha vantage API 发出请求,并处理出现的任何错误(无效标识,无法访问 API 等)。
- 组装我们的响应信息,并在 3 秒内(否则会超时)将其发送回 Slack。
我们将逐步介绍每个需求及其关联的代码,将 Worker 部署到路由中,然后将其连接到 Slack。
Webhook 的处理程序
像所有 Cloudflare Workers 一样,我们需要为 fetch 事件添加一个 hook ,并将入口点(entry point)连接到我们的 Worker 上。slackWebhookHandler
函数将负责触发其余逻辑,并对 Slack 的请求返回 Response 。
1 | // SLACK_TOKEN is used to authenticate requests are from Slack. |
我们的处理程序非常简单:
- 如果传入的请求不是 POST 请求(Slack webhook 接受的是 POST 请求),我们将返回一些有用的(调试)信息。
- 对于 POST 请求,我们检查 POST 表单数据中提供的 token 是否与我们的 token 匹配:这是我们验证 Webhook 来自 Slack 的方式。
- 然后,我们解析用户消息,发出请求获取最新价格,并组装我们的响应信息。
- 如果在此过程中发生任何故障,我们将向用户返回错误信息。
在进行讨论的同时,我们还构建了一些有用的辅助函数:simpleResponse
,用于将生成的错误返回客户端,以及 slackResponse
(稍后将介绍)以 Slack 的预期格式生成响应信息。
SLACK_TOKEN
, BOT_NAME
, 和 ALPHA_VANTAGE_KEY
这些常量,不需要在每个请求中都进行计算,因此我们在请求处理逻辑之外,将它们设为全局变量。
注意:如果要重复使用 Worker 实例本身,则在 Worker 中的请求处理程序之外缓存(通常称为“存储”)静态数据,可在请求之间重用静态数据。尽管这种情况下,性能提升可以忽略不计,但这是一种很好的做法,并且不会影响我们工人的可读性。
解析用户消息
下一步,我们需要解析 Slack 在 POST 请求中发送的消息。这是我们获取请求中股票信息的位置,然后准备将其传递给 Alpha Vantage API。
为了从 API 接收正确的股票信息,我们将解析从 Slack 接收到的输入,以便我们可以将其传递给 API ,来收集有关所需的股票信息。
1 | /** |
让我们逐步完成我们要做的事情:
- 我们传递将用户的消息传到
FormData
- 清洗
FormData
(即去除周围的空格,转换为大写)
将来,如果我们想从 Bot 解析更多的值(也许用户感兴趣的货币汇率或日期),我们可以轻松地向对象添加其他值。
现在有了想要查找的股票信息,我们可以继续进行 API 请求!
发出 API 请求
我们希望确保,我们的机器人不必每次都向 Alpha Vantage API 发出请求:如果每分钟有成千上万的用户向我们发送请求,那么没必要每次都获取(相同的)价格。我们可以按每个 Cloudflare PoP 获取一次,在 Cloudflare 缓存中存储一小段时间(例如1分钟),然后从缓存中拷贝一份提供给用户提。这是双赢的:我们的 bot 响应速度更快,并且我们对所使用的 API 更加友善。
对于订阅了 Enterprise 套餐的客户,您还可以使用 cacheTtlByStatus
功能,这个功能可以让你根据响应状态设置不同的 TTL。这样的情况下,如果你收到了错误代码,则只将其缓存 1 秒钟,或者压根儿就不缓存,这样后续请求(一旦 API 被更新)也不会失败。
确定所请求的股票信息后,我们将向 API 发出 HTTP 请求,确认我们收到可接受的响应(HTTP 200),然后返回的是包含我们需要字段的对象:
1 | let resp = await fetch( |
API 输出的信息,为我们提供了两个元素:元数据和以某个时间间隔的一行数据。就我们的机器人而言,我们将保留 API 提供的最新间隔,并丢弃其余间隔。在将来的迭代中,我们也许会调用月度的 API endpoint,并提供月度高点和低点的信息以进行比较,但是现在我们的需求很简单,只需要最新时间间隔。
我们将使用 Alpha Vantage 提供的每日间隔 API 端点。这将使我们能够为每个单独的股票查询缓存响应,以便下一个向我们的 bot 发出请求的用户可以更快地收到缓存的版本(并且,帮助我们避免受到 API 的频率限制)。在这里,我们将调整为,用来获取最新数据,而不是缓存更长的时间。
你可以看到,我们将向 API 请求以1分钟为间隔的数据。
1 | curl -s "https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=MSFT&interval=1min&apikey=KEY" | jq |
输出如下所示:
1 | { |
要仅获取最后1分钟间隔的数据,我们需要获取 API 提供给我们的最后一个值,并获取其当前的开盘价。
1 | /** |
我们构建一个对象,来代表我们的响应。我们同样需要谨慎处理任何从 API 返回的响应错误:也许是非 HTTP 200 的响应,或者是 非 JSON 的响应。在依赖第三方服务/API 时,必须考虑假设响应的格式或是正确性,这些假设可能会导致程序的异常,从而引起中断,例如,在 HTML 正文上调用 resp.json()。
此外,请注意,后续请求将遵循整个域名的 SSL 模式设置。因此,如果 SSL 模式设置为 flexible,Cloudflare 将尝试通过 80 端口和 HTTP 连接到 API,并且请求将失败(您将看到 525 错误)。
给 Slack 回复响应
Slack 仅对两种格式进行响应:纯文本字符串,或是简单的 JSON 结构。因此,我们需要接受答复,并为 Slack 构建响应。
1 | /** |
slackWebhookHandler
用于处理交易的相应部分,获取我们的回复对象,并将其传递给 slackResponse
-
1 | let reply = await stockRequest(parsed.stock) |
这将返回对 Slack 的响应,如下所示:
1 | { |
配置 Slack 并测试我们的机器人
我们的机器人准备好后,让我们配置 Slack 以便与我们选择的斜杠命令进行对话。首先,登录 Slack 并转到 app management(应用程序管理) 仪表板。
然后,您需要单击 “Create an App(创建应用程序)”,并填写字段,包括指定将其附加到哪个工作区:
然后,我们为他设置为斜杠命令:
填写详细信息:请求 URL 是最重要的,这将反映您将 Worker 附加到的路由。在我们我的情况下,URL 是https://bots.subdomain.workers.dev/
从 Basic Information(基本信息) 标签中获取您的 App Credentials(应用凭据):特别是 Verification Token(验证 token)。
将该值作为 SLACK_TOKEN 变量的值,粘贴到 Worker 机器人中:
1 | // SLACK_TOKEN is used to authenticate requests are from Slack. |
在将我们的机器人连接到 Slack 之前,我们可以进行测试以确保其正确响应。我们可以通过 curl -
模拟 Slack ,发出带有 token 和消息文本的 POST 请求。
1 | # Replace with the hostname/route your Worker is running on |
SLACKTOKENGOESHERE
为正确的 token
bot 回复:
1 | {"response_type":"in_channel","text":"Current price (MSFT): 💵 USD $101.7300","attachments":[]} |
正确的答复应该使我们获得预期的答复。如果我们故意发送无效的 token,则我们的 bot 应做出相应的响应:
1 | curl -X POST https://https://bots.subdomain.workers.dev |
OBVIOUSLYINCORRECTTOKEN
为明显错误的 token
bot 回复:
1 | {"message":"invalid Slack verification token","status":403}% |
或无效的股票代码:
1 | ➜ ~ curl -X POST https://https://bots.subdomain.workers.dev -F "token=SLACKTOKENGOESHERE" -F "text=BADSYMBOL" |
bot 回复:
1 | {"message":"Sorry, I had an issue retrieving anything for that symbol: Error: could not fetch the selected symbol: Error: bad status code from Alpha Vantage: HTTP 404","status":200}% |
如果运行过程中遇到问题,请确保令牌正确(大小写敏感),并且 Alpha Vantage 存在我们要查询的股票。除此之外,我们现在可以将应用安装到我们的 Workspace(工作区)(Slack 会要求您授权机器人):
现在,我们可以通过分配的斜杠命令来调用我们的机器人!
总结
使用 Cloudflare Worker,我们能够建立一个有用的聊天机器人,借助 Cloudflare 的缓存,该机器人可以快速响应(在 Slack 允许的3秒内)。我们对 Alpha Vantage API 也很友善,因为如果我们刚刚才获取了数据,就不必因为请求而再次调用 API。
译者注:部署教程
stock-slack-bot 的代码如下:
1 | // SLACK_TOKEN 用于验证请求来自 Slack. |
在 cloudflare 管理面板,Workers Product 页面,创建一个 worker,将原有的代码替换为以上代码,取个名字,比如叫 stock-slack-bot。
你可以将 stock-slack-bot 绑定给分配的 subdomain.workers.dev,那么 worker 的 URL 为 stock-slack-bot.subdomain.workers.dev.
或者如果你已经有一个域名,比如叫 example.com。切换到你的域名管理界面,有个 worker 标签,设置一条路由规则,stock-slack-bot 到 stock-slack-bot.example.com。
设置好了后,你可以使用上方文章内的 curl 测试 bot 是否可用。