使用 Webhook 向飞书自定义机器人发送消息
飞书自定义机器人允许通过 Webhook 接口接收外部系统推送的消息。本文将介绍如何配置机器人并编写代码发送富文本通知。
1. 创建自定义机器人
首先需要在目标群组中添加机器人。进入群聊右上角菜单,点击'设置',然后选择'群机器人'。点击'添加机器人',找到并选择'自定义机器人'。

添加成功后,在右侧设置界面可以修改机器人的名称、头像及描述。点击'添加'保存。

2. 获取 Webhook 地址与安全设置
在机器人管理页面,找到'安全设置'区域。这里会显示机器人的 Webhook 地址,格式通常为:
https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxxx
请务必妥善保存此地址,避免公开泄露导致被恶意调用。同时,建议开启'签名校验'功能以增强安全性。系统默认提供了一个密钥,你也可以点击'重置'更换新密钥。

3. 核心逻辑:签名校验
飞书要求请求头中包含时间戳和签名。签名计算规则是将 timestamp\nsecret 进行 HMAC-SHA256 加密后 Base64 编码。
注意:时间戳必须是秒级,且需考虑时区问题,不能简单使用 System.currentTimeMillis() / 1000。推荐使用 LocalDateTime 配合时区转换获取标准时间戳。
4. 代码实现
Java 实现
下面是一个完整的 Java 示例,展示了如何构建请求体并发送 POST 请求。
public class FeishuWebhook {
private static final Logger logger = LoggerFactory.getLogger(FeishuWebhook.class);
public static final String DEFAULT_DATETIME_FORMATTER_STR ;
DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMATTER_STR);
{
logger.info(, url, alertDO);
createRequestBody(secret, alertDO);
logger.info(, requestBody);
HttpUtils.postForJsonObject(url, , , requestBody);
logger.info(, result);
}
String NoSuchAlgorithmException, InvalidKeyException {
timestamp + + secret;
Mac.getInstance();
mac.init( (stringToSign.getBytes(StandardCharsets.UTF_8), ));
[] signData = mac.doFinal( []);
(Base64.encodeBase64(signData));
}
JSONObject {
();
LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
logger.info(, seconds);
{
genSign(secret, seconds);
requestBody.put(, seconds);
requestBody.put(, sign);
requestBody.put(, );
;
alertDO.getMessage();
alertDO.getDetail();
DEFAULT_DATETIME_FORMATTER.format(LocalDateTime.ofInstant(alertDO.getStartTime().toInstant(), ZoneId.systemDefault()));
DEFAULT_DATETIME_FORMATTER.format(LocalDateTime.ofInstant(alertDO.getEndTime().toInstant(), ZoneId.systemDefault()));
requestBody.put(, createOuterContent(title, message, detail, startTime, endTime));
} (Exception e) {
e.printStackTrace();
}
requestBody;
}
JSONObject {
();
result.put(, createPostJsonObject(title, message, detail, startTime, endTime));
result;
}
JSONObject {
();
result.put(, createZhCNJsonObject(title, message, detail, startTime, endTime));
result;
}
JSONObject {
();
result.put(, title);
result.put(, createContentList(message, detail, startTime, endTime));
result;
}
JSONArray {
();
();
item1.add(createInnerHeadContent());
item1.add(createInnerTextContent(message));
result.add(item1);
();
item2.add(createInnerHeadContent());
item2.add(createInnerTextContent(detail));
result.add(item2);
();
item3.add(createInnerHeadContent());
item3.add(createInnerTextContent(startTime));
result.add(item3);
();
item4.add(createInnerHeadContent());
item4.add(createInnerTextContent(endTime));
result.add(item4);
result;
}
JSONObject {
();
result.put(, );
result.put(, tag + );
result;
}
JSONObject {
();
result.put(, );
result.put(, text);
result;
}
}


