发送webhook到飞书机器人
参考链接 自定义机器人使用指南
创建自定义机器人
邀请自定义机器人进群。
进入目标群组,在群组右上角点击更多按钮,并点击 设置。
在右侧 设置 界面,点击 群机器人。
在 群机器人 界面点击 添加机器人。
在 添加机器人 对话框,找到并点击 自定义机器人。
设置自定义机器人的头像、名称与描述,并点击 添加。
获取自定义机器人的 webhook 地址
机器人对应的 webhook 地址 格式如下:
https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxxx
请妥善保存好此 webhook 地址,不要公布在 Gitlab、博客等可公开查阅的网站上,避免地址泄露后被恶意调用发送垃圾消息。
获取签名校验
在 安全设置 区域,选择 签名校验。
选择签名校验后,系统已默认提供了一个秘钥。你也可以点击 重置,更换秘钥。
使用java发送http post到自定义机器人
- 计算签名校验,参考官方文档的SignDemo.java,自定义一个签名函数
private static String genSign(String secret, long timestamp) throws NoSuchAlgorithmException, InvalidKeyException {
//把timestamp+"\n"+密钥当做签名字符串
String stringToSign = timestamp + "\n" + secret;
//使用HmacSHA256算法计算签名
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] signData = mac.doFinal(new byte[]{});
return new String(Base64.encodeBase64(signData));
}
- 计算时间戳
需要注意的是,时间戳是以秒为单位的,并且要配置时区,不可直接使用System.currentTimeMillis()/1000来计算秒值
long seconds = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
- 创建富文本消息
参考官方文档 发送富文本消息- 创建一个content对象
private static JSONObject createOuterContent(String title, String message, String detail, String startTime, String endTime) {
JSONObject result = new JSONObject();
result.put("post", createPostJsonObject(title, message, detail, startTime, endTime));
return result;
}
private static JSONObject createPostJsonObject(String title, String message, String detail, String startTime, String endTime) {
JSONObject result = new JSONObject();
result.put("zh_cn", createZhCNJsonObject(title, message, detail, startTime, endTime));
return result;
}
private static JSONObject createZhCNJsonObject(String title, String message, String detail, String startTime, String endTime) {
JSONObject result = new JSONObject();
result.put("title", title);
result.put("content", createContentList(message, detail, startTime, endTime));
return result;
}
private static JSONArray createContentList(String message, String detail, String startTime, String endTime) {
JSONArray result = new JSONArray();
JSONArray item1 = new JSONArray();
item1.add(createInnerHeadContent("message"));
item1.add(createInnerTextContent(message));
result.add(item1);
JSONArray item2 = new JSONArray();
item2.add(createInnerHeadContent("detail"));
item2.add(createInnerTextContent(detail));
result.add(item2);
JSONArray item3 = new JSONArray();
item3.add(createInnerHeadContent("startTime"));
item3.add(createInnerTextContent(startTime));
result.add(item3);
JSONArray item4 = new JSONArray();
item4.add(createInnerHeadContent("endTime"));
item4.add(createInnerTextContent(endTime));
result.add(item4);
return result;
}
private static JSONObject createInnerHeadContent(String tag) {
JSONObject result = new JSONObject();
result.put("tag", "text");
result.put("text", tag+": ");
return result;
}
private static JSONObject createInnerTextContent(String text) {
JSONObject result = new JSONObject();
result.put("tag", "text");
result.put("text", text);
return result;
}
- 再创建完整的json对象
完整代码如下
java版本
public class FeishuWebhook {
private static final Logger logger = LoggerFactory.getLogger(FeishuWebhook.class);
public static final String DEFAULT_DATETIME_FORMATTER_STR = "yyyy-MM-dd HH:mm:ss";
public static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER =
DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMATTER_STR);
public static void send(String url, String secret, AlertDO alertDO) {
logger.info("FeishuWebhook.send, url:{}, alertDO={}", url, alertDO);
JSONObject requestBody = createRequestBody(secret, alertDO);
logger.info("requestBody:{}", requestBody);
JSONObject result = HttpUtils.postForJsonObject(url, null, null, requestBody);
logger.info("result:{}", result);
}
private static String genSign(String secret, long timestamp) throws NoSuchAlgorithmException, InvalidKeyException {
//把timestamp+"\n"+密钥当做签名字符串
String stringToSign = timestamp + "\n" + secret;
//使用HmacSHA256算法计算签名
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] signData = mac.doFinal(new byte[]{});
return new String(Base64.encodeBase64(signData));
}
private static JSONObject createRequestBody(String secret, AlertDO alertDO) {
JSONObject requestBody = new JSONObject();
long seconds = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
logger.info("seconds:{}", seconds);
// int seconds = 1734515343;
try {
String sign = genSign(secret, seconds);
requestBody.put("timestamp", seconds);
requestBody.put("sign", sign);
requestBody.put("msg_type", "post");
String title = "通知";
String message = alertDO.getMessage();
String detail = alertDO.getDetail();
String startTime = DEFAULT_DATETIME_FORMATTER.format(LocalDateTime.ofInstant(alertDO.getStartTime().toInstant(), ZoneId.systemDefault()));
String endTime = DEFAULT_DATETIME_FORMATTER.format(LocalDateTime.ofInstant(alertDO.getEndTime().toInstant(), ZoneId.systemDefault()));
requestBody.put("content", createOuterContent(title, message, detail, startTime, endTime));
} catch (Exception e) {
e.printStackTrace();
}
return requestBody;
}
private static JSONObject createOuterContent(String title, String message, String detail, String startTime, String endTime) {
JSONObject result = new JSONObject();
result.put("post", createPostJsonObject(title, message, detail, startTime, endTime));
return result;
}
private static JSONObject createPostJsonObject(String title, String message, String detail, String startTime, String endTime) {
JSONObject result = new JSONObject();
result.put("zh_cn", createZhCNJsonObject(title, message, detail, startTime, endTime));
return result;
}
private static JSONObject createZhCNJsonObject(String title, String message, String detail, String startTime, String endTime) {
JSONObject result = new JSONObject();
result.put("title", title);
result.put("content", createContentList(message, detail, startTime, endTime));
return result;
}
private static JSONArray createContentList(String message, String detail, String startTime, String endTime) {
JSONArray result = new JSONArray();
JSONArray item1 = new JSONArray();
item1.add(createInnerHeadContent("message"));
item1.add(createInnerTextContent(message));
result.add(item1);
JSONArray item2 = new JSONArray();
item2.add(createInnerHeadContent("detail"));
item2.add(createInnerTextContent(detail));
result.add(item2);
JSONArray item3 = new JSONArray();
item3.add(createInnerHeadContent("startTime"));
item3.add(createInnerTextContent(startTime));
result.add(item3);
JSONArray item4 = new JSONArray();
item4.add(createInnerHeadContent("endTime"));
item4.add(createInnerTextContent(endTime));
result.add(item4);
return result;
}
private static JSONObject createInnerHeadContent(String tag) {
JSONObject result = new JSONObject();
result.put("tag", "text");
result.put("text", tag+": ");
return result;
}
private static JSONObject createInnerTextContent(String text) {
JSONObject result = new JSONObject();
result.put("tag", "text");
result.put("text", text);
return result;
}
}
python版本
FeishuBotHypertextWithSecret.py
import base64
import hashlib
import hmac
from datetime import datetime
import requests
WEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/xx"
WEBHOOK_SECRET = "ssssssss"
class LarkBot:
def __init__(self, secret: str) -> None:
if not secret:
raise ValueError("invalid secret key")
self.secret = secret
def gen_sign(self, timestamp: int) -> str:
string_to_sign = '{}\n{}'.format(timestamp, self.secret)
hmac_code = hmac.new(
string_to_sign.encode("utf-8"), digestmod=hashlib.sha256
).digest()
sign = base64.b64encode(hmac_code).decode('utf-8')
return sign
def send(self) -> None:
timestamp = int(datetime.now().timestamp())
sign = self.gen_sign(timestamp)
params = {
"timestamp": timestamp,
"sign": sign,
"msg_type": "post",
"content": {
"post": {
"zh_cn": {
"title": "项目更新通知",
"content": [
[{
"tag": "text",
"text": "项目有更新: "
}, {
"tag": "a",
"text": "请查看",
"href": "http://www.example.com/"
}, {
"tag": "at",
"user_id": "ou_18eac8********17ad4f02e8bbbb"
}]
]
}
}
}
}
resp = requests.post(url=WEBHOOK_URL, json=params)
resp.raise_for_status()
result = resp.json()
if result.get("code") and result["code"] != 0:
print(result["msg"])
return
print("消息发送成功")
def main():
bot = LarkBot(secret=WEBHOOK_SECRET)
bot.send()
if __name__ == '__main__':
main()
LarkBotWithoutSecret.py
from datetime import datetime
import requests
WEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/sss"
class LarkBot:
def send(self, content: str) -> None:
timestamp = int(datetime.now().timestamp())
params = {
"timestamp": timestamp,
"msg_type": "text",
"content": {"text": content},
}
resp = requests.post(url=WEBHOOK_URL, json=params)
resp.raise_for_status()
result = resp.json()
if result.get("code") and result["code"] != 0:
print(result["msg"])
return
print("消息发送成功")
def main():
bot = LarkBot()
bot.send(content="我是一只高级鸽子!")
if __name__ == '__main__':
main()