Index
概要
在本文中,我们要讨论的是kintone的Webhook。
Webhook是一种HTTP回调,在特定事件发生时,它会向某个URL发送HTTP POST请求,从而实现事件通知。
kintone提供了App的“添加记录、编辑记录、删除记录、填写回复、更新状态”5种回调事件。
需要注意的是,kintone的批量操作不会触发回调。
通过本文的学习,我们将会从零开始,一步步开发一个可运行的kintone Webhook服务。
技术选型
在传统的业务逻辑下,要搭建可用的Web服务,需要部署服务器、搭建HTTP服务、开放防火墙端口等很多运维任务。
但是在云环境普及的今天,搭建Web服务变得非常简单,甚至连服务器都不需要购买,只需使用Serverless技术即可。
Serverless,在AWS下被称为Lambda,而Aliyun上则被称为函数计算。
其本质是云服务厂商提供基础设施服务(vps、k8s、docker等),而开发者只需关注和上传自己的应用代码。
在使用费用方面,各家云厂商也有一定的免费额度。
例如,在AWS(海外版)中,免费额度为“每月100万次免费请求和400,000 GB秒的计算时间”。
这个额度对于Demo演示或小型应用来说非常友好。
综合来看,Serverless技术非常适合短时间的触发式请求、或者定时执行且运行时间不超过15分钟的程序。
本地开发环境
在接下来的内容中,我们将基于AWS Lambda开发一款Serverless程序,用于处理kintone的Webhook请求。
考虑到serverless的冷启动问题,我们需要选择一门启动时间较快的语言。
本次会使用Nodejs的TLS版本。如果你已安装了Nodejs,请注意和AWS的支持版本相适配。
安装Serverless Framework,作为开发、部署工具。
在终端中运行以下命令:
npm install -g serverless
请注意,在3.27.0 (2023-01-26)之前的版本中,一旦发现用户位于中国大陆区域,Serverless Framework会强制安装Tencent CLI,并屏蔽AWS模版。
到截稿为止,新版本虽然移除了默认安装,但同样有设置环境变量的需求。
因此,中国大陆区域的用户需要在环境变量中添加以下值:
SLS_GEO_LOCATION=no-cn
最后还需要让kintone能够访问到我们的程序端口,因此需要一个内网映射程序。
这里使用的是ngrok。
安装模板
在终端中运行以下命令:
sls
然后选择HTTP API,按照提示输入项目名称,本文将其命名为“webhookdemo”。
如果由于网络问题而无法加载模板,请直接下载模板。
接下来需要安装serverless-offline,它将模拟 AWS Lambda 的运行时,以本地服务器的方式启动。
在终端中运行以下命令:
cd webhookdemo sls plugin install -n serverless-offline
进入项目根目录,安装serverless-offline。
修改模板
打开项目根目录的 servless.yml 文件,进行以下修改:
首先是httpApi中的path和method。
在这里,path就是网址路径,我们这里把它定义为“/webhook”。
而method则是HTTP请求的方法,这里我们需要把它改成“post”,因为kintone的Webhook只会发送post请求。
同时需要注意的是,不要使用比本地的Nodejs版本更高的版本号。
最后在index.js的handler函数中,我们打印一下传递进来的参数。
启动服务
在项目根目录的命令行中输入以下命令,启动本地服务器(默认端口为3000):
sls offline
然后打开一个新的终端,输入以下命令:
ngrok http 3000
开启3000端口的外网映射,并记录下其中的Forwarding地址:
这个URL就是我们的Webhook的测试 URL的domain,需要记下来用于在kintone中配置。
kintone设置
打开需要配置Webhook的应用,在应用设置中选择Webhook。
点击“添加”,填写以下信息:
最后别忘了 更新应用。
测试
现在我们已经完成了Webhook的配置和部署,可以开始测试了。
在kintone中进行一些配置好的操作,例如添加记录、编辑记录等。
触发事件后,kintone就会向我们部署的Lambda函数发送Webhook请求。
我们的代码在收到请求后,会完整的打印请求信息。
为了只响应kintone的Webhook请求,我们可以限制user-agent为kintone-Webhook/0.1的请求才被处理。
因为user-agent是区分Webhook和普通浏览器请求的主要手段。
发送通知
Body是通知的主体,为Json格式,参数如下:
添加记录/编辑记录/更新记录的状态
参数 | 值的类型 | 说明 |
---|---|---|
id | 字符串 | 分配给每个通知的唯一的ID。 |
type | 字符串 | 操作的类型。 添加了记录:ADD_RECORD 编辑了记录:UPDATE_RECORD 更改了记录的状态:UPDATE_STATUS |
app | 对象 | 代表应用信息的对象。 |
app.id | 文本框 | 应用的ID。 |
app.name | 文本框 | 应用名称。 |
record | 对象 | 代表记录信息的对象。 对象的格式与获取记录的REST API相同。 获取记录(GET)(日语)(cybozu developer network) |
recordTitle | 字符串 | 记录的标题。 可更改要设置为标题的字段。 设置记录标题 |
url | 字符串 | 记录的URL。 |
发送通知的范例
{ "id":"01234567-0123-0123-0123-0123456789ab", "type":"ADD_RECORD", "app":{ "id":"1", "name":"案件管理" }, "record":{ "记录编号":{ "type":"RECORD_NUMBER", "value":"2" }, ~~ "$revision":{ "type":"__REVISION__","value":"3" }, "$id":{ "type":"__ID__","value":"2" } }, "recordTitle":"拜访:才望子", "url":"https://example.cybozu.com/k/1/show#record=2" }
删除记录
参数 | 值的类型 | 说明 |
---|---|---|
id | 字符串 | 分配给每个通知的唯一的ID。 |
type | 字符串 | 操作的类型。 删除了记录:DELETE_RECORD |
app | 对象 | 代表应用信息的对象。 |
app.id | 文本框 | 应用的ID。 |
app.name | 文本框 | 应用名称。 |
recordId | 字符串 | 记录编号。不包含应用代码。 |
deleteBy | 对象 | 代表删除记录的用户信息的对象。 |
deletedBy.code | 文本框 | 用户的登录名。 |
deletedBy.name | 文本框 | 用户的姓名。 |
deleteAt | 字符串 | 删除的日期与时间。 |
发送通知的范例
{ "app":{ "id":"1", "name":"案件管理" }, "id":"01234567-0123-0123-0123-0123456789ab", "recordId":"2", "deleteBy":{ "code":"sato", "name":"佐藤 升" }, "deleteAt":"2017-07-03T09:38:09Z", "type":"DELETE_RECORD" }
填写回复
参数 | 值的类型 | 说明 |
---|---|---|
app | 对象 | 代表应用信息的对象。 |
app.id | 文本框 | 应用的ID。 |
app.name | 文本框 | 应用名称。 |
comment | 对象 | 代表回复信息的对象。 对象的格式与批量获取记录回复的REST API相同。 批量获取记录的回复(日语)(cybozu developer network) |
id | 字符串 | 分配给每个通知的唯一的ID。 |
recordId | 字符串 | 记录编号。不包含应用代码。 |
type | 字符串 | 操作的类型。 填写了回复:ADD_RECORD_COMMENT |
url | 字符串 | 回复的URL。 |
发送通知的范例
{ "app":{ "id":"1", "name":"案件管理" }, "comment":{ "createdAt":"2012-02-03T09:38:09Z", "creator":{ "code":"kato", "name":"加藤 美咲" }, "id":"11", "mentions":[ { "code":"kato", "type":"USER" }, { "code":"org1", "type":"ORGANIZATION" }, { "code":"group1", "type":"GROUP" } ], "text":"我来拜访才望子了。" }, "id":"01234567-0123-0123-0123-0123456789ab", "recordId":"2", "type":"ADD_RECORD_COMMENT", "url":"https://example.cybozu.com/k/1/show#record=2&comment=11" }
应用场景
获取kintone的请求主体后,我们可以在代码中对接其他API。
比如我们可以将Webhook的返回内容推送给钉钉或其他的聊天软件。
又或者将其转存到其他kintone。
注意,除了“填写回复”事件,其他的事件都有着对应的JS事件。
因此,Webhook的开发对比自定义JS开发,其成本并不占优。
只有当你的JS上传权限被限制,又或者需要填写回复时触发某些操作时,才会考虑kintone的Webhook。
正式部署
最后简单说一下Serverless Framework的部署方式。
之前的serverless-offline和ngrok组合,仅适用于本地调试。
要想让我们的代码正式运行起来,还必须将其部署到AWS的Lamdba上。
如果你是第一次使用Serverless Framework,请进行配置:
serverless config credentials --provider provider --key key --secret secret
然后使用以下命令上传代码:
sls deploy
注意:你的账号必须拥有对应的权限,才能正常部署。
在默认配置下,我们就可以通过以下地址来访问:
https://${your_id}.execute-api.${your_region}.amazonaws.com/${your_path}
最后
如果你的项目,使用了第三方的库,那么最好对生成的代码进行压缩整合,以更好的对应冷启动问题。
这里就不赘述了,有兴趣的请查看Serverless Framework官方文档。
下一篇 在 Microsoft Power Automate HTTP 操作中执行任意 kintone REST API