软件分享-飞书模板消息测试工具

大家好,我是快乐IT

开发背景

公司有一套较旧的业务系统,对接飞书后在移动端显示一直有问题。但老系统已经不具备二开条件,想改也没法改。可审批通知又不能不发,总不能让业务同学天天盯着电脑等消息吧。

于是我就想,能不能在系统外部挂一层,用一种轻量的方式把飞书推送这件事给解决了------不改动老系统代码,也能让相关人员及时收到审批通知。

软件介绍

飞书模板消息测试工具 是一个基于 .NET 8 WinForm 的桌面应用,填入参数即可一键发送飞书卡片消息,带着跳转按钮直达审批页面。

主要功能:

  • 获取Token --- 通过 App ID + App Secret 自动获取飞书 tenant_access_token
  • 发送卡片消息 --- 推送带标题、正文、跳转按钮的互动卡片,适合审批通知场景
  • 发送文本消息 --- 推送纯文本消息,满足简单通知需求
  • 配置自动保存 --- App ID、App Secret、User ID、跳转URL 等参数关闭时自动持久化,下次打开无需重填

界面采用左右布局,左侧操作区,右侧品牌区,日志区采用深色终端风格,操作反馈一目了然。

异常处理

  • 双击程序没反应或闪退 --- 本工具基于 .NET 8 开发,需要安装 .NET 8.0 运行时windowsdesktop-runtime-8.0.28-win-x64.exe,约55MB)。前往微软官网下载安装后重试。
  • 获取Token失败 --- 检查 App ID 和 App Secret 是否填写正确,确保飞书应用已创建并审核通过。
  • 发送消息返回权限不足 --- 飞书应用需开通 im:message:send_as_bot 权限,在飞书开放平台后台添加该权限并重新发布应用。
  • 消息发送成功但收不到 --- 确认 User ID 填写正确,receive_id_typeuser_id 时需要填写飞书用户的 User ID,不是姓名。

核心开发过程

开发过程中有几点值得分享的点:

Token 自动刷新机制。 飞书的 tenant_access_token 有效期 2 小时,我提前 60 秒标记过期,发送消息前自动检查并刷新,避免因 Token 过期导致发送失败。这个细节很容易被忽略,但一旦上线后偶发失败就很难排查。

飞书API对接

飞书消息发送的核心流程分两步:获取Token → 发送消息

第一步:获取 tenant_access_token
csharp 复制代码
public async Task<(bool success, string token, string message)> GetTokenAsync()
{
    using var client = new HttpClient();
    var body = new { app_id = _appId, app_secret = _appSecret };
    var content = new StringContent(
        JsonConvert.SerializeObject(body),
        Encoding.UTF8, "application/json");

    var response = await client.PostAsync(
        "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
        content);
    var result = await response.Content.ReadAsStringAsync();
    var json = JObject.Parse(result);

    if (json["code"]?.Value<int>() == 0)
    {
        _accessToken = json["tenant_access_token"]?.Value<string>();
        var expire = json["expire"]?.Value<int>() ?? 7200;
        _tokenExpireTime = DateTime.Now.AddSeconds(expire - 60); // 提前60秒过期
        return (true, _accessToken ?? "", "获取Token成功");
    }
    // ...错误处理
}

要点:Token 有效期 2 小时,我们提前 60 秒标记过期,并在发送消息前自动刷新:

csharp 复制代码
private async Task<string?> EnsureTokenAsync()
{
    if (_accessToken != null && DateTime.Now < _tokenExpireTime)
        return _accessToken;  // 未过期,复用
    var (success, token, _) = await GetTokenAsync();
    return success ? token : null;
}
第二步:发送互动卡片消息

飞书互动卡片(Interactive Card)支持富文本标题、正文、按钮跳转,非常适合审批通知场景:

csharp 复制代码
var card = new
{
    config = new { wide_screen_mode = true },
    header = new
    {
        title = new { tag = "plain_text", content = title },  // 可自定义标题
        template = "blue"
    },
    elements = new object[]
    {
        new { tag = "div", text = new { tag = "plain_text", content = content } },
        new
        {
            tag = "action",
            actions = new object[]
            {
                new
                {
                    tag = "button",
                    text = new { tag = "plain_text", content = "点击审批" },
                    url = url,       // 跳转到审批页面
                    type = "primary"
                }
            }
        }
    }
};

var body = new
{
    receive_id = userId,
    msg_type = "interactive",
    content = JsonConvert.SerializeObject(card)
};

调用飞书 /im/v1/messages 接口发送,receive_id_type=user_id 表示按用户ID发送。