飞书通知机器人

目标 & 背景

前段时间钉钉的 webhook 机器人,进行了改版,现如今已经和企业微信通知差不多了,比之前麻烦了很多,正好我司接下来要换到飞书,借着这个机会对飞书的机器人相关内容熟悉了一下

首先明确在接入机器人时,我希望最终接入时,仅需要引入 shell 脚本,不需要借助其他语言二次开发

创建企业 app

首先来到 飞书开放平台,创建企业自建应用,对于通知类型的机器人,我们需要添加 机器人 能力,以及对应的通知权限

这里的权限一般需要企业的管理员进行审核后,才可以使用

消息卡片模板

飞书提供了很多种消息类型,其中我个人比较喜欢的是 card 类型,可以完成很多复杂的消息推送,而且飞书还通了一个可视化的搭建工具,具体可点击链接尝试 消息卡片搭建工具

这里我使用模板 ID 作为推送的类型,因此需要在变量列表中配置通知时需要上传的参数列表,如 我是内容 这段文字对应的 markdown 信息,就需要传入 content 变量,基于这种配置方式,我们在搭建好通知后台后,可以随意修改卡片的样式等信息

访问凭证

获取访问凭证文档

飞书的官方文档还是非常不错的,我们这里使用的是第一种 tenant_access_token,这里主要讲一下如何将请求的返回结果取出我们要的字段

curl -X POST 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal' \
-H 'Content-Type: application/json' \
-d '{
	"app_id": "xxx",
	"app_secret": "xxx"
}'

在执行这段代码后,飞书会返回如下内容

{
  "code": 0,
  "expire": 3096,
  "msg": "ok",
  "tenant_access_token": "t-xxx"
}

我们需要的是最后一段 tenant_access_token 对应的字符串,这里需要借助 jq 指令的辅助,我们只需要在请求的最后加入 | jq -r '.tenant_access_token' 即可

token=$(curl -X POST 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal' \
-H 'Content-Type: application/json' \
-d '{
	"app_id": "xxx",
	"app_secret": "xxx"
}' | jq -r '.tenant_access_token')

echo $token

群 ID

在我们调用最后的发送 API 之前,需要明确这条消息到底发给谁,我这里的需求是发送到专门的通知群中,因此需要透过飞书的 API 获取正确的群 ID

在 API 调试界面,手动获取 token 后,飞书会直接返回给你当前机器人所在的所有群的基本信息,具体返回参考如下

{
  "code": 0,
  "data": {
    "has_more": false,
    "items": [
      {
        "avatar": "xxx",
        "chat_id": "xxx",
        "description": "",
        "external": false,
        "name": "xxx",
        "owner_id": "xxx",
        "owner_id_type": "open_id",
        "tenant_key": "xxx"
      }
    ],
    "page_token": ""
  },
  "msg": "success"
}

这里的 chat_id 对应的值就是我们所需要的

发送消息

发送消息文档

这个部分我们主要做的是对 send 行为进行封装,并处理好字符串的转换。在发送之前,我们需要准备好如下参数

  • receive_id_type 这里是 chat_id
  • tenant_access_token
  • receive_id 对应群的 chat_id
  • template_id 对应 card 模板 ID
  • template_variable 对应 card 模板中的变量
  • app_id 机器人应用 ID
  • app_secret 机器人的 sign
#!/bin/bash

raw_content='
{
  "type":"template",
  "data":
  {
    "template_id":"xxx", # 填入你的模板ID
    "template_variable":
    {
      "title":"我是标题",  # 这里可以封装为函数,使用 $1 等参数进行接收
      "content":"我是内容",
      "btn_name":"我是按钮",
      "btn_url":"https://www.baidu.com"
    }
  }
}
'

# 飞书对于 content 的定义为 string,因此这里必须是一个转义后的 json
# 比如 "type":"template" 就必须是 \"type\":\"template\"
# 借助 jq 的 tostring 方法,可以保证上面模板 json 的书写体验
content=$(echo $raw_content | jq -c '.|tostring')

card='
{
	"msg_type": "interactive",
	"receive_id": "xxx", # 群的 chat_id
	"content":'$content'
}
'
token=$(curl -X POST 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal' \
-H 'Content-Type: application/json' \
-d '{
	"app_id": "xxx", # 企业应用的 app_id
	"app_secret": "xxx" # 企业应用的 sign
}' | jq -r '.tenant_access_token')

curl -i -X POST 'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id' \ 
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer '$token'' \
-d "$card"

一些恶趣味

在我使用过程中发现,card 后台也可以动态配置图片,而且飞书也支持 gif 格式,这就有意思了,搭建工具可以手动上传你需要的图片,记录下来这张图片的 key,然后在 shell 脚本中根据情况选择不同的 key,这样就可以有不同的通知效果

虽然飞书也支持 api upload 图片,但是我懒的写了~

我把通知的三种类型,对应了三个不同 魔性八哥 的表情包

  • 开始打包
  • 打包成功
  • 打包失败

哈哈哈哈哈,这个通知非常欢乐,你都不用看文字,就知道结果

最后

这次了解了一下飞书的通知,对比了一下钉钉的 webhook,差距非常明显