一个面向 Go 的 Telegram Bot API SDK,模块路径为:
github.com/ijnkawakaze/telegram-bot-api
它在标准 BotAPI 之上增加了一层 Bot 处理器,适合快速编写轮询机器人,也保留完整的底层 Telegram API 调用能力。
- 支持长轮询和 Webhook。
- 支持命令、私聊命令、回调查询、图片消息、回复消息、内联查询、入群/退群、入群申请等处理器。
- 内置等待用户下一条消息、临时回调查询、权限校验、延迟删除消息等常用能力。
- 提供
CallbackData、ExpiringSet、MessageCleaner等工具类型。 - 大部分类型和方法使用中文注释,便于阅读。
- 当前同步到 Telegram Bot API 10.2。
go get github.com/ijnkawakaze/telegram-bot-api如果你在本地修改了 SDK,并希望另一个项目直接使用本地工作区,可以在 go.mod 中增加:
replace github.com/ijnkawakaze/telegram-bot-api => ../telegram-bot-api../telegram-bot-api 是相对目标项目模块文件的路径,请按实际目录调整。
package main
import (
"log"
tgbotapi "github.com/ijnkawakaze/telegram-bot-api"
)
func main() {
bot, err := tgbotapi.NewBotAPI("YOUR_BOT_TOKEN")
if err != nil {
log.Fatal(err)
}
bot.Debug = true
handler := bot.AddHandle()
handler.NewCommandProcessor("start", func(update tgbotapi.Update) error {
if update.Message == nil {
return nil
}
_, err := update.Message.Reply("你好,我是机器人", bot)
return err
})
handler.Run()
}NewBotAPI 会立即调用 getMe 获取机器人信息;失败时返回错误,可以提前发现 token 或网络问题。
BotAPI 是最底层的 Telegram API 客户端:
bot, err := tgbotapi.NewBotAPI("TOKEN")它负责:
- 发送请求:
bot.Send(config) - 原始请求:
bot.Request(config) - 获取更新:
bot.GetUpdatesChan(config) - 文件下载:
bot.GetFileDirectURL(fileID)
Bot 是处理器和状态层:
handler := bot.AddHandle()Bot 内嵌了 *BotAPI,所以 handler 也可以直接调用 Send、SendText 等 API 方法:
handler.SendText(chatID, "hello")推荐做法是:
- 用
bot处理 Telegram API 调用。 - 用
handler注册命令、回调和等待状态。 - 最后调用
handler.Run()启动长轮询。
message := tgbotapi.NewMessage(chatID, "hello")
message.ParseMode = tgbotapi.ModeMarkdownV2
bot.Send(message)也可以使用快捷方法:
bot.SendText(chatID, "hello")
bot.SendMarkdownV2(chatID, "**hello**", messageID)
bot.ReplyText(chatID, messageID, "回复这条消息")data, _ := os.ReadFile("photo.jpg")
bot.SendPhotoBytes(chatID, data, "photo.jpg")doc := tgbotapi.NewDocument(chatID, tgbotapi.FilePath("./report.pdf"))
doc.Caption = "报告"
bot.Send(doc)常用的文件表示:
tgbotapi.FileBytes{Name: "x.jpg", Bytes: data}tgbotapi.FileReader{Name: "x.jpg", Reader: reader}tgbotapi.FilePath("path/to/file")tgbotapi.FileURL("https://example.com/file.jpg")
photo := tgbotapi.NewInputMediaPhoto(tgbotapi.FilePath("1.jpg"))
video := tgbotapi.NewInputMediaVideo(tgbotapi.FileURL("https://example.com/v.mp4"))
mediaGroup := tgbotapi.NewMediaGroup(chatID, []interface{}{photo, video})
bot.SendMediaGroup(mediaGroup)所有处理器的签名都是:
func(update tgbotapi.Update) errorhandler.NewCommandProcessor("start", func(update tgbotapi.Update) error {
chatID := update.ChatID()
userID := update.UserID()
text := "欢迎使用机器人"
_, err := bot.SendText(chatID, text)
return err
})handler.NewPrivateCommandProcessor("bind", bindHandler)当消息中包含照片且 Caption 以指定命令开头时触发:
handler.NewPhotoMessageProcessor("/ocr", func(update tgbotapi.Update) error {
photo := update.Message.Photo
// 处理图片
return nil
})当用户回复某条消息并发送指定命令时触发:
handler.NewReplyMessageProcessor("/report", reportHandler)handler.NewInlineQueryProcessor("搜索", func(update tgbotapi.Update) error {
if update.InlineQuery == nil {
return nil
}
result := tgbotapi.NewInlineQueryResultArticle(
update.InlineQuery.ID,
"标题",
"结果描述",
)
answer := tgbotapi.InlineConfig{
InlineQueryID: update.InlineQuery.ID,
Results: []interface{}{result},
}
_, err := bot.Request(answer)
return err
})更多内联结果构造函数见 helpers.go。
handler.NewCallBackProcessor("choose", func(update tgbotapi.Update) error {
query := update.CallbackQuery
if query == nil {
return nil
}
query.Answer(false, "", bot)
return nil
})回调数据通常使用逗号分隔:
data := tgbotapi.NewInlineKeyboardButtonData(
"选择 A",
"choose,A,123",
)handler.NewCallBackProcessor("choose", func(update tgbotapi.Update) error {
data := tgbotapi.ParseCallbackData(update.CallbackData())
action := data.StringAt(0) // "choose"
itemID := data.StringAt(1) // "A"
id, err := data.Int64At(2) // 123
if err != nil {
return err
}
_ = id
return nil
})也可以构造回调数据:
callbackData := tgbotapi.NewCallbackData("choose", "A", 123)
button := tgbotapi.NewInlineKeyboardButtonData("选择", callbackData.String())有些流程需要先问用户一个问题,再等待用户回复。
handler.NewWaitMessageProcessor("setToken", func(update tgbotapi.Update) error {
token := update.Message.Text
// 处理用户输入的 token
return nil
})handler.SetWaitMessage(userID, "setToken")清除或检查等待状态:
handler.ClearWaitMessage(userID)
if handler.HasWaitMessage(userID) {
// 用户仍处于等待输入状态
}如果需要把上一步的数据带到下一步处理器:
handler.NewWaitContextProcessor("choosePlayer", func(update tgbotapi.Update, data any) error {
uid := data.(string)
_, _ = bot.SendText(update.ChatID(), "你选择了:"+uid)
return nil
})
handler.SetWaitMessage(userID, "choosePlayer", "player-123")临时回调适合“只在短时间内有效,且只能由指定用户触发”的按钮。
callbackID, err := handler.RegisterEphemeralCallback(
func(update tgbotapi.Update) error {
_, err := bot.SendText(update.ChatID(), "你点击了临时按钮")
return err
},
5*time.Minute,
userID,
)
if err != nil {
return err
}
button := tgbotapi.NewInlineKeyboardButtonData("确认", callbackID)回调一旦被触发就会自动删除。
handler.NewAdminCommandProcessor("ban", banHandler)handler.NewAdminCommandProcessorWithPermissions(
"delete",
tgbotapi.AdminCanDeleteMessages,
deleteHandler,
)handler.SetOwnerID(123456789)
handler.NewOwnerCommandProcessor("update", updateHandler)
handler.NewOwnerPrivateCommandProcessor("admin", adminHandler)protected := handler.RequireAdmin(tgbotapi.AdminCanRestrictMembers, myHandler)
handler.NewCommandProcessor("mute", protected)常用权限常量:
tgbotapi.AdminCanRestrictMembers
tgbotapi.AdminCanDeleteMessages
tgbotapi.AdminCanPromoteMembers
tgbotapi.AdminCanPostMessages
tgbotapi.AdminCanEditMessages
tgbotapi.AdminCanPinMessages
tgbotapi.AdminCanManageChathandler.NewMemberProcessor(func(update tgbotapi.Update) error {
// 新成员入群
return nil
})
handler.LeftMemberProcessor(func(update tgbotapi.Update) error {
// 成员退群或被移出
return nil
})
handler.JoinRequestProcessor(func(update tgbotapi.Update) error {
// 处理 ChatJoinRequest
return nil
})底层管理能力:
bot.RestrictChatMember(chatID, userID, tgbotapi.NoMessagesPermission)
bot.BanChatMember(chatID, userID)
bot.UnbanChatMember(chatID, userID)
bot.ApproveChatJoinRequest(chatID, userID)
bot.DeclineChatJoinRequest(chatID, userID)body, extension, err := bot.DownloadFile(fileID)
if err != nil {
return err
}
defer body.Close()data, extension, err := bot.DownloadFileBytes(fileID)update.Message.Delete(bot)
update.CallbackQuery.Delete(bot)update.Message.DeleteAfter(10*time.Second, bot)cleaner := tgbotapi.NewMessageCleaner(bot)
defer cleaner.Close()
cleaner.DeleteAfter(chatID, messageID, 5*time.Second)MessageCleaner.Close() 会等待正在执行的删除任务结束。
适合保存“待验证成员”“临时授权”等有过期时间的状态。
set := tgbotapi.NewExpiringSet()
set.Add(userKey, 5*time.Minute)
if set.Contains(userKey) {
// 尚未过期
}
if set.Pop(userKey) {
// 取出并删除,且尚未过期
}基础用法:
bot, err := tgbotapi.NewBotAPI("TOKEN")
if err != nil {
log.Fatal(err)
}
updates := bot.ListenForWebhook("/" + bot.Token)
for update := range updates {
// 处理 update
}
http.ListenAndServe(":8443", nil)也可直接处理单个请求:
update, err := bot.HandleUpdate(r)Webhook 部署时还需要在 Telegram 侧设置:
https://你的域名:8443/<bot_token>
生产环境建议使用 Nginx 或 Caddy 提供 TLS。
text := tgbotapi.EscapeText(tgbotapi.ModeMarkdownV2, "hello_world")
bot.SendMarkdownV2(chatID, text)if bot.IsMessageToMe(update.Message) {
// 处理
}me, err := bot.GetMe()bot.go BotAPI 客户端、HTTP 请求、轮询和 Webhook
configs.go Telegram API 请求配置类型
types.go Telegram API 对象类型
helpers.go 创建请求配置的构造函数
custom.go Bot 处理器、等待状态、临时回调和增强快捷方法
passport.go Telegram Passport 相关类型
params.go HTTP 参数处理
当同时开发 SDK 和业务项目时,推荐使用 replace 指向本地目录:
// 业务项目 go.mod
replace github.com/ijnkawakaze/telegram-bot-api => ../telegram-bot-api然后在业务项目中:
bot, _ := tgbotapi.NewBotAPI("TOKEN")
handler := bot.AddHandle()如果业务代码只需要一个变量,也可以让 Bot 同时承担 API 和处理器职责:
bot := &tgbotapi.Bot{BotAPI: api}