最稳妥的方式是直接使用 slack-go/slack 库发消息,因其已封装字段规范、事件签名校验、block kit 排布及自动重试等细节,避免手动拼 json 导致的大小写错误、emoji 转义失败、交互支持缺失等问题。

直接用 slack-go/slack 库发消息最稳妥,别自己拼 JSON;Webhook 模式适合简单通知,Socket Mode 才能响应 @ 或按钮点击。
为什么不用自己写 HTTP POST 发 Slack?
自己构造 JSON + net/http 看似轻量,但很快会踩坑:字段名大小写错(text 不是 Text)、嵌套结构漏空数组、emoji 转义失败、附件字段没按 Block Kit 规范排布。更麻烦的是,一旦要支持交互(比如点击按钮触发操作),就得自己解析事件签名、校验 timestamp、处理 response_url 回调——这些 slack-go/slack 都已封装好。
实操建议:
- 用
slack.New()初始化客户端时,优先传botToken(格式为xoxb-...),不是 Webhook URL;后者只够发单向消息 - 发普通文本用
api.PostMessage(channelID, slack.MsgOptionText("hi", false)),第二个参数控制是否启用 markdown - 发带按钮的富媒体消息,必须用
slack.MsgOptionBlocks()传入[]slack.Block,不能塞进text字段 - 别在日志里打印完整
botToken,哪怕只是 debug 模式;用slack.OptionDebug(true)时它会自动脱敏
Webhook 和 Socket Mode 到底怎么选?
Webhook 是“你推它收”,适合 CI/CD 完成后发个状态;Socket Mode 是“它推你收”,才能监听用户 @ 机器人、点击消息里的按钮、或收到某频道新消息。两者认证方式、错误重试逻辑、连接生命周期完全不同。
实操建议:
- 只要需求里有“用户主动触发”(比如
@bot deploy prod),就必须用 Socket Mode,Webhook 做不到 - Socket Mode 需要先在 Slack App 后台开启 “Socket Mode”,并填入 App-Level Token(
xapp-...),不是 Bot Token - Webhook 模式下,
SLACK_WEBHOOK_URL环境变量值必须是完整 URL,开头是https://hooks.slack.com/services/...,少一个字符都会返回 404 - Socket Mode 连接断开时,库会自动重连,但你要确保
slack.New()传入的slack.OptionAppLevelToken和slack.OptionBotToken都正确,否则重连失败静默退出
Block Kit 消息里怎么安全插变量?
Slack 的 Block Kit 不支持模板语法,所有动态内容都得在 Go 里拼好再传进去。直接字符串拼接容易引入 XSS 风险(比如用户输入含 ``` 或 >),也容易破坏 JSON 结构。
实操建议:
- 用
slack.NewTextBlockObject(slack.MarkdownType, text, false, false)构造文本块,第三个参数false表示不解析内部 markdown,避免用户输入干扰格式 - 用户输入内容(如 PR 标题、错误日志片段)必须过一遍
strings.ReplaceAll(text, "`", "'"),防止三重反引号提前闭合代码块 - 构建
slack.SectionBlock时,Fields数组长度不能超过 10,超了 Slack API 会拒收;宁可拆成两个 section,别硬塞 - 时间戳字段(
ts)必须是 Unix 秒级整数字符串,比如fmt.Sprintf("%d", time.Now().Unix()),传 float 或毫秒值会报错invalid_ts
本地调试时收不到消息?先查这三处
本地跑通 slack-go/slack 最常见的卡点不是代码,而是 Slack 后台配置和网络策略。
实操建议:
- 确认 Bot Token 对应的 Slack App 已安装到目标工作区,且在 “OAuth & Permissions” 页面里勾选了
chat:write、channels:read等必要 scope - 发消息用的
channelID必须是 ID(如C012AB3CD),不是频道名(如#general);用api.GetConversations()查 ID,别手敲 - 公司内网可能屏蔽
slack.com域名或限制 WebSocket,Socket Mode 会卡在Connecting...;临时切到手机热点测试,快速验证是不是网络问题
真正难的不是发一条消息,而是让消息在不同场景下都“稳”:频道被归档、用户被移出、token 过期、Slack API 限流——这些边界情况,slack-go/slack 的错误码和重试策略已经覆盖了大部分,但你要读清文档里每个 error 类型对应的 recovery 方式,而不是只 catch 一个 err != nil。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











