用飞书Webhook接收实时告警

阅读 12
标签: Java

对于小型官网或轻量业务系统,使用飞书自定义机器人(Webhook) 是一种性价比高、开发快、体验极佳的实时通知方案。

比如下面场景:

  • 当官网收到潜在客户咨询时
  • 当某个API接口被恶意调用时
  • 当服务器的资源出现压力时

常常需要一种实时的通知让我们第一时间知道情况。

飞书 Webhook的优势

飞书的Webhook具有如下优势:

  • 实时响应:只要提交请求,手机和电脑端的飞书几乎秒级收到弹窗通知。
  • 零成本:无需购买短信包或邮件发送服务。
  • 接入简单:只需向飞书地址发送一个 POST 请求即可。

整体实现流程

实现起来很简单。

第一步:在飞书中新建一个群聊。

第二步:进入群设置点击 群机器人,添加机器人,选择自定义机器人,点击添加。会获得这个机器人的Webhook URL,如下图所示:

拿到这个地址后,事情就可以完成60%了。

最后一步,就是写代码测试能否正常收到信息。这里以Spring + Java代码示例:

@Test
public void sendFeishu() {
    var restClient = RestClient.create();

    // 1. 构造消息内容(必须包含你设置的关键词,比如“告警”)
    int uid = 1001;
    String reason = "使用量超出限制";
    String text = String.format("【系统告警】\n异常用户ID: %s\n原因: %s\n时间: %s",
            uid, reason, LocalDateTime.now());

    try {
        // 2. 使用 RestClient 发送流式请求
        restClient.post()
                .uri(webhookUrl)
                .contentType(MediaType.APPLICATION_JSON)
                .body(FeishuMessage.ofText(text))
                .retrieve()
                .onStatus(HttpStatusCode::isError, (request, response) -> {
                    log.error("飞书接口返回错误状态码: {}", response.getStatusCode());
                })
                .toBodilessEntity(); // 我们不需要飞书返回的 Body,只要成功就行

        log.info("飞书告警发送成功,针对 UID: {}", uid);
    } catch (Exception e) {
        log.error("调用飞书 Webhook 发生异常", e);
    }
}

使用 Spring 提供的 RestClient 来向这个机器人的Webhook地址推送测试消息。

如果正常,会在上面新建的那个群聊中收到如下消息:

消息推送是实时的,非常快。

安全问题

如果担心 Webhook 地址泄露被他人恶意调用,可以在飞书机器人后台开启签名校验(Signature Verification)。在上图中的安全设置中,勾选 签名校验,会生成一个密钥。

以 Java 为例,获取当前时间戳以及密钥后,可以使用如下方法来生成签名字符串:

private static String generateSign(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));
}

然后,构建如下JSON请求体即可:

String sign = generateSign(secret, timestamp);

// 构造带签名校验的请求 Payload
Map<String, Object> payload = Map.of(
        "timestamp", String.valueOf(timestamp),
        "sign", sign,
        "msg_type", "text",
        "content", Map.of("text", msg)
);

将之前的 FeishuMessage.ofText(text)  换成上面的 payload 形式传入即可。

这样,每次请求时都会向webhook地址发送如下形式的json数据:

{
        "timestamp": "1599360473",        // 时间戳。
        "sign": "xxxxxxxxxxxxxxxxxxxxx",  // 得到的签名字符串。
        "msg_type": "text",
        "content": {
                "text": "request example"
        }
}

相比未使用签名校验,json数据中多了timestampsign字段。

Webhook服务器收到客户端请求的数据后,会使用timestamp和secret来进行客户端同样的hmac计算,如果得到的sign和客户端传递的sign相同,则通过校验;否则,则拒绝访问。

除了签名校验外,还可以开启IP白名单自定义关键词这两个额外安全设置。

参考

最后编辑于: 2026-08-16

评论(0条)

(必填)
复制成功