大家好,我是快乐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_type为user_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发送。