自定义机器人使用指南
自定义机器人添加入口
- 在群聊中点击右上角的「···」图标,点击群机器人;
- 点击添加 webhook 机器人;
- 填写机器人名称和简介,即可添加自定义机器人到群聊中。

如何使用自定义机器人
- 在终端某个群组添加机器人之后,可以获取到 webhook 地址,然后开发者用户按以下说明构造 post data 向这个地址发起 HTTP POST 请求,即可实现给该群组发送消息
- webhook 格式是:https://xz.wps.cn/api/v1/webhook/send?key=xxxxxxx
- 特别特别要注意:一定要保护好机器人的 webhook 地址,避免泄漏!不要分享到 github、博客等可被公开查阅的地方,否则坏人就可以用你的机器人来发垃圾消息了
相关限制
- 消息发送频率限制:每个机器人发送的消息不能超过 20 条/分钟
- 消息内容阈值:每条消息不超过 5000 个字符
文本类型
参数说明
| 参数 | 是否必填 | 说明 |
|---|---|---|
| msgtype | 是 | 消息类型。text-表示文本类型 |
| text | 是 | 文本消息 |
| ∟ content | 是 | 消息内容 |
支持通过在消息体 content 中插入<at>标签的方式@人,如果不填写姓名,则服务端将自动填充姓名至@人位置:
- 使用 id@人:<at user_id="12345">姓名</at>
- 使用 email@人:<at email="somebody@wps.cn">姓名</at>
- @所有人:<at user_id="-1">所有人</at>
代码示例
{
+ "msgtype":"text",
+ "text":{
+ "content":"每日数据监控报告:\n今日数据统计结果请相关同事注意<at user_id=\"17856\">李三</at><at user_id=\"-1\">所有人</at>"
+ }
+}
+展示示例

Markdown 类型
参数说明
| 参数 | 是否必填 | 说明 |
|---|---|---|
| msgtype | 是 | 消息类型 |
| markdown | 是 | markdown 消息 |
| ∟ text | 是 | 消息内容 |
代码示例
{
+ "msgtype": "markdown",
+ "markdown": {
+ "text":"## KAE监控报警\n\n报警内容:网关入口\n\n> 备注:严重程度中等"
+ }
+}
+展示示例

说明:目前只支持 md 语法的子集,具体支持的元素如下(换行可以使用“双空格+\n”或“\n\n”方式),不同语法之间的组合(颜色+标题等)。
| 名称 | 语法 | 说明 |
|---|---|---|
| @人 | 使用 id@人:<at user_id="12345">姓名</at> 使用 email@人:<at email="somebody@wps.cn">姓名</at> @所有人:<at user_id="-1">所有人</at> | / |
| 标题 | # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题 | / |
| 引用 | > 引用内容 | / |
| 加粗 | **加粗** | 如移动端显示有问题可尝试在后面加空格 |
| 颜色 | <font color='#FF0000'>颜色</font> <font color='red'>颜色</font> | 支持使用十六进制颜色值或对应颜色的英文表示 |
| 斜体 | *斜体* _斜体_ | / |
| 删除线 | ~~删除线~~ | / |
| 链接 | <链接地址> [链接名称](链接地址) | / |
| 有序列表 | 1. 内容 1 2. 内容 2 | / |
| 无序列表 | - 内容 1 - 内容 2 | / |
| 图片 |  | / |
链接类型
参数说明
| 参数 | 是否必填 | 说明 |
|---|---|---|
| msgtype | 是 | 消息类型。link-表示链接类型 |
| title | 是 | 标题内容 |
| text | 是 | markdown 格式的消息。换行可以使用“双空格+\n”或“\n\n”方式。 |
| messageUrl | 否 | 跳转 url |
| btnTitle | 否 | 按钮标题,默认为“查看详情”,长度限制 12 个字符 |
代码示例
{
+ "msgtype": "link",
+ "link": {
+ "title": "日程提醒",
+ "text": "需求评审会将于15分钟后开始↵2F-201会议室",
+ "messageUrl": "https://kdocs.cn",
+ "btnTitle": "查看详情"
+ }
+}
+展示示例

卡片类型
参数说明
| 参数 | 是否必填 | 说明 |
|---|---|---|
| msgtype | 是 | 消息类型。card-表示卡片类型 |
| card | 是 | 卡片消息,具体内容见搭建卡片消息,备注:目前 webhook 不支持回传型交互组件, 包括回传型按钮、列表选择器、日期选择器、输入框 |
代码示例
{
+ "msgtype":"card",
+ "card":{
+ "header":{
+ "title":{
+ "tag":"text",
+ "content":{
+ "type":"plainText",
+ "text":"标题"
+ }
+ },
+ "subtitle":{
+ "tag":"text",
+ "content":{
+ "type":"plainText",
+ "text":"副标题"
+ }
+ }
+ },
+ "elements":[
+ {
+ "tag":"text",
+ "content":{
+ "type":"markdown",
+ "text":"普通文本"
+ }
+ }
+ ],
+ "i18n":{
+ "zh-TW":{
+ "header":{
+ "title":{
+ "tag":"text",
+ "content":{
+ "type":"plainText",
+ "text":"標題"
+ }
+ },
+ "subtitle":{
+ "tag":"text",
+ "content":{
+ "type":"plainText",
+ "text":"副標題"
+ }
+ }
+ },
+ "elements":[
+ {
+ "tag":"text",
+ "content":{
+ "type":"markdown",
+ "text":"普通文本"
+ }
+ }
+ ]
+ },
+ "en-US":{
+ "header":{
+ "title":{
+ "tag":"text",
+ "content":{
+ "type":"plainText",
+ "text":"title"
+ }
+ },
+ "subtitle":{
+ "tag":"text",
+ "content":{
+ "type":"plainText",
+ "text":"sub title"
+ }
+ }
+ },
+ "elements":[
+ {
+ "tag":"text",
+ "content":{
+ "type":"markdown",
+ "text":"common text"
+ }
+ }
+ ]
+ }
+ }
+ }
+}
+展示示例

自定义机器人添加 callback
机器人添加 callback

callback 可用性校验
创建者在输入框中输入 url,点击保存。服务端会对该地址进行一次 GET 请求,例如:
[GET] https://xz.wps.cn/api/v1/test
第三方收到请求后返回以下 response 数据即可:
{"result":"ok"}
+即代表该请求可用。
callback 发送消息
当群聊中用户 at 创建者所配置的 webhook 机器人时,服务端会把该条 at 消息通过 POST 请求发送给第三方,例如:
[POST] https://xz.wps.cn/api/v1/test
请求参数
| 参数 | 类型 | 位置 | 说明 |
|---|---|---|---|
| chatid | int64 | body | 会话 id |
| creator | int64 | body | 发送者 id |
| content | string | body | 内容 |
| reply | object | body | 回复内容 |
| robot_key | string | body | 机器人 key |
| url | string | body | callback 地址创建者所填的 url 地址 |
| ctime | int64 | body | 发送时间 |
| 参数 reply | 类型 | 位置 | 说明 |
|---|---|---|---|
| reply_content | string | body | 回复内容 |
| reply_creator | int64 | body | 回复消息发送者 id |
请求参数示例
{
+ "chatid": 12345,
+ "creator": 2324234,
+ "content": "@webhook机器人 111",
+ "reply": {
+ "reply_content": "回复内容",
+ "reply_creator": 1234
+ },
+ "robot_key": "xxx",
+ "url": "https://xxxx",
+ "ctime": 3452452
+}
+返回结果示例
{"result":"ok"}
+自定义机器人安全设置
如果开发者未保管好 webhook 地址,可能存在地址泄漏后被恶意用来发送垃圾信息的风险,建议开发者至少选择配置一个安全设置。
自定义关键词
设置后,发送的消息需包含至少一个关键词,最多设置 10 个关键词。
示例:设置了关键词:报警、告警后,通过 webhook 机器人发送的消息需带有至少一个关键词,才可以发送成功。
IP 白名单
设置后,只处理来自 IP 白名单地址范围内的请求,最多设置 10 个 IP 地址/地址段,如:192.168.1.1 或 192.168.1.1/24 或 192.168.1.*。
签名校验
设置后,发送请求时需要签名验证来保障信息来源可信。
- 用户可以在 HTTP Header 中包含签名 (Authorization)。
- 签名头 (Authorization)验证码计算方法如下:Authorization:" key + ":" + sha1( secret_key + Content-Md5 + Content-Type + DATE)。
注意: HTTP Header 中必须包含以下字段
- Content-Md5 HTTP Body 中数据的 md5 值十六进制表达方式, 必需小写。
- Content-Type 目前固定为: application/json。
- DATE 取当前时间, 格式: Wed, 23 Jan 2013 06:43:08 GMT,签名默认有效时间为 15 分钟。
- Authorization 上面所说的签名头。
特权用户设置
设置后,只有群主、管理员和 webhook 机器人的添加者,可以编辑或移除此机器人。

完整 HTTP 实例
Header
POST https://xz.wps.cn/api/v1/webhook/send
+Content-Md5: d41d8cd98f00b204e9800998ecf8427e
+Content-Type: application/json
+DATE: Wed, 19 Oct 2021 02:16:08 GMT
+Authorization:63840ea636369968f9e0de63c0ee02a1:2b9725f94fcf45216edb5392fa540e2083c25b6f
+go 示例代码
var calcContentMD5 string
+ // 检查Date是否超过15分钟
+ dateTime, err := time.Parse(layout, webhookSendRequest.Date)
+ if err != nil {
+ return robot.ErrWebhookSendByTimestamp
+
+ }
+ deltaTime := time.Now().Sub(dateTime)
+ if deltaTime < -15*time.Minute || deltaTime > 15*time.Minute {
+ return robot.ErrWebhookSendByTimestamp
+
+ }
+
+ // 检查Content-Md5
+ contentMD5Array := md5.Sum(webhookSendRequest.Content)
+ calcContentMD5 = hex.EncodeToString(contentMD5Array[:])
+ if webhookSendRequest.ContentMD5 != calcContentMD5 {
+ return robot.ErrWebhookSendBySign
+ }
+
+ //获取sign
+ splits := strings.Split(webhookSendRequest.Auth, ":")
+ if len(splits) != 2 {
+ return robot.ErrWebhookSendBySign
+
+ }
+ // 计算签名
+ str := secretKey + webhookSendRequest.ContentMD5 + webhookSendRequest.ContentType + webhookSendRequest.Date
+ sigBytes := sha1.Sum([]byte(str))
+ sig := hex.EncodeToString(sigBytes[:])
+ if sig != splits[1] {
+ return robot.ErrWebhookSendBySign
+ }
+