本篇文章聊聊轻量的网络钩子(WebHook)工具:歪脖虎克。
写在前面
这是一篇迟到很久的文章,在 21 年和 22 年的时候,我分享过两篇关于轻量的计划任务工具 Cronicle 的文章:《轻量的定时任务工具 Cronicle:前篇》、《使用 Docker 和 Traefik 搭建轻量美观的计划任务工具》。随后在文章的评论区和聊天群里,以及一些关联的开源项目 issue 区里,我总是能够收到关于最佳使用实践的问题。
我一般都会推荐将 Cron 工具和 WebHook 工具结合使用,说到具体的 WebHook 的时候,我当时一般都推荐“GitHub 上我 fork 的那个开源软件”:soulteary/webhook。
四年前,在我 fork 的软件仓库几乎不在更新后,原始项目的技术债务堆积越来越严重。
最近正好在折腾异步流程比较多的模型应用,正好把这个项目也顺带做一个翻新(开源分叉)。关于项目具体分叉的原因,我会在文末再做详细展开。
好啦,让我们开始折腾。
前置知识
鉴于文章的读者可能是新用户,那么让我们从前置知识的展开开始吧。
什么是 WebHook
WebHook 是一种常见的网络软件功能,通常用于连接异步的处理过程。直接介绍 WebHook 是什么会比较无趣,我们不妨参考 zapier 的 “WebHook 和 API 的异同” 来更直观的了解下 WebHook 的工作模式。
相比较我们熟悉的 API 调用,尽管他们都能够将数据从一个地方发送到另外一个地方,完成数据的交互,但是通常 WebHook 都是异步、单向的,不强制要求即刻返回数据结果。
通常情况下,支持 WebHook 的功能的软件中能够定义一些自定义回调函数(Custom Callback Function),来让其他的外部程序在合适的时候调用这些函数,让一些被预先定义好的程序被调用,特别适合一些场景:
- 比如,常见的耗时比较久的程序执行完毕,推送信息到用户,可以回调一个通知接口。
- 比如,常见的多次跳转的支付过程,当用户扫码授权后,银行接口会回调我们购买商品的平台,告诉平台用户付款了。
歪脖虎克(soulteary/WebHook)是什么
歪脖虎克(WebHook)是一个用 Go 语言编写的轻量可配置的实用工具,它允许你轻松、快速的创建 HTTP 服务(钩子)。
你可以使用它来执行配置好的命令。并且还能够将 HTTP 请求中的数据(如请求头内容、请求体以及请求参数)灵活的传递给你配置好的命令、程序。当然,它也允许根据具体的条件规则来便触发钩子。
举个例子,如果你使用的是 GitHub 或 Gitea,可以使用歪脖虎克设置一个钩子,在每次你推送更改到项目的某个分支时,这个钩子会在你运行服务的设备上运行一个“更新程序部署内容”的脚本。
如果你使用飞书、钉钉、企业微信或者 Slack,你也可以设置一个“传出 Webhook 集成”或“斜杠命令”,来在你的服务器上运行各种命令。我们可以通过聊天工具的“传入 Webhook 集成”功能处理接口的响应内容,直接向你或你的 IM 会话或频道报告执行结果。
歪脖虎克(WebHook)的项目目标非常简单,只做它应该做的事情:
- 接收请求
- 解析请求头、请求体和请求参数
- 检查钩子指定的运行规则是否得到满足
- 最后,通过命令行参数或环境变量将指定的参数传递给指定的命令
至于具体的命令,从处理数据、存储数据到用远程命令打开空调、关闭电脑,一些都由你做主,你可以实现任何你想要的事情,它只负责在合适的时间点,接受执行指令。
准备工作
开始实战之前,需要先获取程序文件。
下载“歪脖虎克”程序
目前下载程序有两个方法,下载在 GitHub 上通过自动化构建工具构建完毕的内容。
或者,使用 Docker 来快速下载程序。
# 下载最新的版本
docker pull soulteary/webhook:latest
# 下载指定版本的镜像
docker pull soulteary/webhook:3.4.5
# 下载包含了常用工具的镜像
docker pull soulteary/webhook:extend-3.4.5
当我们完成程序下载后,就可以开始使用啦。
查看软件文档(可选)
你可以在开源代码仓库的 docs
目录找到软件的中文使用文档,里面记录了:钩子的定义方法、具体的配置参数、如何解析和对请求参数进行调用命令参数绑定、各种常见的调用示例方法。
接下来,我们以一个简单的日常场景进行配置说明:使用 WebHook 和聊天工具进行联动,推送通知信息。
设置飞书的 WebHook 功能
其实我们日常使用的各种聊天工具,基本都支持使用 WebHook 方式进行交互。
我这里以飞书为例,来实现一个能够从外部调用飞书 WebHook 发送消息的机器人。
和其他的聊天软件类似,在飞书里创建机器人的最简方案是先创建一个“聊天群组”。
创建完毕后,戳开右上角的下拉菜单,找到“设置”选项。
进入设置选项后,能够看到群组的详细设置。
点击“机器人”设置,能够看到一个新的弹出框,包含了许多不同类型的机器人。
这里,我们选择自定义机器人(WebHook)。
在机器人配置界面中进行详细的自定义配置,比如可以设置个好看的头像,或者起个有趣的名字。
点击确定,我们就能够得到 WebHook 程序调用所需要的接口地址啦。保存好地址,我们一会要用到。
点击完成,机器人就被添加到群组中啦。
到这里为止,飞书的配置就完啦。
我们可以使用下面的命令,来验证接口是否能够被正确调用。
curl -X POST -H "Content-Type: application/json" --data '{"msg_type":"text","content":{"text":"嘿,你好呀👋"}}' \
https://open.feishu.cn/open-apis/bot/v2/hook/6dca9854-381a-4bb9-a87b-33a222833e04
调用完毕,会出现类似下面的返回结果:
{"StatusCode":0,"StatusMessage":"success","code":0,"data":{},"msg":"success"}
在飞书的界面中,我们能够看到新出现的消息内容。
接下来,我们来把“歪脖虎克”和飞书连接在一起,让程序内容能够动态化。
实战开始
在本文中,歪脖虎克可以将上面我们调用飞书 WebHook 接口的命令,赋予动态化调用的能力,并且提供更简单的调用接口,甚至提供额外的“接口验证”、关联的自动化处理信息能力。比如,当程序被调用的时候,能够根据具体的输入信息,结合上下文相关的资料,调用大模型接口,发送一段有趣的故事到群里。
考虑到复现的方便,我使用 Docker 环境的 “歪脖虎克”,直接使用二进制文件类似,只需要调整命令,在次不做赘述。
编写调用程序
我们先实现一个简单的程序,能够接收来自环境变量中的参数 $TEXT
,并将参数中的内容传递到上面的飞书调用命令中(soulteary/webhook/example/lark/send-lark-message.sh):
#!/bin/sh
if [ -n "$TEXT" ]; then
curl -X POST -H "Content-Type: application/json" --data {\"msg_type\":\"text\",\"content\":{\"text\":\"$TEXT\"}} \
https://open.feishu.cn/open-apis/bot/v2/hook/6dca9854-381a-4bb9-a87b-33a222833e04
echo "Send message successfully".
else
echo "TEXT is empty"
fi
将上面的程序保存为 send-lark-message.sh
(替换为你自己的飞书 API 地址)。然后我们对这个脚本赋予可执行权限:
chmod +x send-lark-message.sh
这里,我们也可以将上面的脚本程序替换成某些具备特定功能的程序,比如进行数据处理的程序,查询或者导出数据库文件的程序,调用大模型的能力等等。
编写配置文件
接下来,我们来编写一个让“歪脖虎克”来调用这个脚本的程序(soulteary/webhook/example/lark/hook-lark.yaml):
- id: lark
execute-command: ./send-lark-message.sh
command-working-directory: /app
include-command-output-in-response: true
include-command-out-in-response-on-error: true
pass-environment-to-command:
- source: url
name: text
envname: TEXT
我们将上面的内容保存为 hook-lark.yaml
,“歪脖虎克” 的基本配置就准备完毕啦。
在上面的程序配置中,我们做了两件事,分别是:
- 创建一个用于触发远程接口(飞书API)的脚本程序
send-lark-message.sh
,能够在用户设置环境变量TEXT
的时候,将环境变量内容传递到飞书发送消息参数中。 - 创建了一个
id` 是 `lark
的 WebHook 配置,当 WebHook 被调用时,会自动调用位于/app
目录的send-lark-message.sh
脚本程序,将 URL 请求参数中的text
内容转换为环境变量,传递给脚本程序,然后将脚本程序的执行结果展示给调用的用户。
编写容器配置文件或直接调用程序
为了稳定复现,我们再编写一个 docker-compose.yml
配置文件:
version: '2'
services:
webhook:
image: soulteary/webhook:extend-3.4.5
ports:
- 9000:9000
environment:
HOST: "0.0.0.0"
PORT: 9000
VERBOSE: true
HOOKS: "/app/hook-lark.yaml"
volumes:
- ./hook-lark.yaml:/app/hook-lark.yaml
- ./send-lark-message.sh:/app/send-lark-message.sh
保存这个配置文件和上面的两个配置到相同的目录后,我们执行 docker compose up
,程序将运行在本机的 9000
端口。
如果你想直接运行程序,可以使用下面的命令:
./webhook --hooks ./example/lark/hook-lark.yaml --verbose
一切顺利,你将看到类似下面的日志内容:
lark-webhook-1 | [webhook] 2024/04/06 07:52:11 version [3.4.5] starting
lark-webhook-1 | [webhook] 2024/04/06 07:52:11 setting up os signal watcher
lark-webhook-1 | [webhook] 2024/04/06 07:52:11 attempting to load hooks from /app/hook-lark.yaml
lark-webhook-1 | [webhook] 2024/04/06 07:52:11 os signal watcher ready
lark-webhook-1 | [webhook] 2024/04/06 07:52:11 found 1 hook(s) in file
lark-webhook-1 | [webhook] 2024/04/06 07:52:11 loaded: lark
lark-webhook-1 | [webhook] 2024/04/06 07:52:11 serving hooks on http://0.0.0.0:9000/hooks/{id}
我们打开浏览器,访问 http://0.0.0.0:9000/hooks/lark?text=hey
,将会很快得到下面的内容(命令行执行返回):
当我们再次打开飞书的界面,能够看到消息已经发送到飞书中啦。当然,这个工具并非只能连接一个 API ,你可以通过它将一堆服务都关联起来,进行一些自动化操作,或者做一些需要定时、被动触发自动化处理的工作。
还记得之前文章提到的实现“计划任务”的 Cronicle 小工具吗?你可以通过类似这样的方法,将计划任务中的具体实现,都使用“歪脖虎克”来实现,而将任务调度和编排交给 Cronicle,这样的话,你可以分别维护不同的程序,甚至在合适的情况下,灵活的切换程序为其他的组件。
其他:为什么要进行开源分叉
在项目的文档中,我提到了主要有两个原因:
第一个是,原作者维护的 webhook
程序版本,是从比较陈旧的 Go 程序版本慢慢升级上来的。
其中,包含了许多不再被需要的内容,以及非常多的安全问题亟待修正。
第二个是,我在几年前曾经提交过一个改进版本的 PR,但是因为种种原因被作者忽略,与其继续使用明知道不可靠的程序,不如将它变的可靠。
这样,除了更容易从社区合并未被原始仓库作者合并的社区功能外,还可以快速对有安全风险的依赖作更新。除此之外,我希望这个程序接下来能够中文更加友好,包括文档。
当然,开源软件世界里,talk is cheap, code is everything.
,目前看来,这个硬分叉项目应该是及格的吧 :D
最后
好啦,这篇文章就先写到这里,后面相关的文章中,我会试着分享一些更有趣的具体(偷懒)实践。
下篇文章再见。
–EOF