用 Go 寫出我的第一個 Telegram Bot:go-bot 專案心得

作者: Calpa Liu
字數:2741
出版:2025 年 11 月 27 日
分類: 後端開發 GoTelegram BotSide Project
一直想用 Go 做一個實戰專案,最後選擇從 Telegram Bot 開始。這篇文章會分享為什麼我用 Go,go-bot 專案的架構設計,以及如何在本機與雲端部署一個 Webhook-based Telegram Echo Bot。

一直以來,我都喜歡用新技術做一些小專案,從前端框架到部署平台,只要覺得有趣、有挑戰性,就會忍不住想親手試一次。這次的主角是 Go 和 Telegram Bot。我做了一個小小的專案:calpa/go-bot,用 Go 寫成、以 Webhook 為基礎的 Telegram Echo Bot。表面上它只是一個會把訊息原封不動加上前綴再回傳的機器人,但對我來說,它代表的是一個完整串起來的實戰:從本機環境、到 Telegram API、再到雲端服務。

這篇文章想記錄幾件事。首先是為什麼會選擇用 Go 來寫 Telegram Bot,接著看看 go-bot 這個專案實際在做什麼,再一路走到它的架構設計、關鍵程式碼和環境設定,最後回到它在本機與雲端實際跑起來時的樣子。這些步驟拆開來都不複雜,但串在一起,會讓人很清楚地感受到「原來我真的用 Go 把一個可以被世界使用的小服務搭起來了」。

為什麼用 Go 寫 Telegram Bot?

我對 Go 的好感來自幾個很直觀的特點。它的編譯速度很快,對開發者來說幾乎沒有「等 build」的痛苦,可以很自然地進入一種快速嘗試的節奏。同時,語言本身把並行當成一等公民,goroutine 和 channel 的設計,讓人很容易想像未來要在同一個服務裡做更多事情時,系統會長成什麼樣子。再加上 Go 編譯出來是一個單一 binary,部署非常乾淨,很適合放上各種雲端平台。

Telegram Bot 則是一個非常適合拿來練習的小題目。它的 API 清楚、文件齊全,只要有一個 HTTP server,提供一個可以接收 Webhook 的 endpoint,就能完成最基本的互動。對我來說,目標很簡單:用 Go 寫一個乾淨、單純,但架構清楚的 Echo Bot。它不需要一開始就做很多事,只要日後想加功能時,不會被一團糊在一起的程式碼卡住就好。

go-bot 就是在這樣的前提下長出來的。

專案本身在做什麼?

在談細節架構之前,先從使用者的角度看,這個 bot 到底在做什麼會比較直覺。從功能層面來看,go-bot 做的事情其實很純粹。當程式啟動時,它會建立一個 HTTP server,預設監聽在 :8000。這個 server 有三個路由。根路由 / 回傳一個非常傳統的文字回應 Hello World,算是確認服務已經正常啟動。/telegram/webhook 則是給 Telegram 發送更新用的 endpoint,當使用者在 Telegram 裡對 bot 說話時,Telegram 會把相關的 Update 結構 POST 到這個路徑。最後一個路由 /set-webhook 則是一個小助手,用來幫我從程式本身呼叫 Telegram 的 setWebhook API,把 Webhook 設定到正確的網址上。

當有訊息進來時,實際處理邏輯發生在 handler 裡。現在的行為非常簡單:如果這次的更新裡沒有 Message,就直接忽略;如果有,就先把收到的文字印到 log,然後再透過 SendMessage 回到同一個聊天裡,訊息內容是前面加上 Echo: 的原文。換句話說,Telegram 變成了一個可以幫你確認系統是不是正常運作的介面,你打什麼,它就幫你回聲一次。

從 main.go 看整體架構

雖然整個專案目前只有一個 main.go 檔案,但我在寫的時候還是刻意把各個職責拆開,讓未來如果要分成不同 package,不會太痛苦。整個流程從 main 函式開始。程式一啟動會先呼叫 loadEnv(),透過 github.com/joho/godotenv 將專案根目錄下的 .env 載入到環境變數裡。這一步是為了後面能夠用 os.Getenv 拿到 Telegram bot token 和 Webhook 相關設定。

接著,我用 signal.NotifyContext 建立了一個會在收到 os.Interrupt(也就是 Ctrl+C)時自動被取消的 context.Context。這個 context 會一路傳遞到整個 HTTP server 和 bot 的生命周期中,最後用來觸發優雅關機。然後是 newBot(),這個函式會讀取 TELEGRAM_BOT_TOKENTELEGRAM_WEBHOOK_SECRET_TOKEN,建立一個 *bot.Bot。同時,我在這裡把預設的 handler 設成自己的 handler 函式,也把 Webhook 的 secret token 傳給 SDK,讓它在處理 Webhook 請求時能進行驗證。

botClient.StartWebhook(ctx) 則是整個 Telegram 面向的啟動點。當這個 goroutine 跑起來之後,只要有請求打到 /telegram/webhook,由 SDK 提供的 WebhookHandler 就會把資料轉成 Update 結構,然後交給我們定義好的 handler 處理。HTTP 層的部分則是交給 newMux(botClient)newServer(mux)。前者負責把 //telegram/webhook/set-webhook 這三個路由都掛到同一個 http.ServeMux 上,後者則是回傳一個 *http.Server,將位址設定為 :8000,並且把 mux 傳給它。

真正啟動 server 的工作發生在 startServer(ctx, srv)。這個函式會在 goroutine 裡呼叫 ListenAndServe,同時印出 HTTP server listening on :8000 這句提示。另一邊它會卡在 <-ctx.Done(),一旦我們在終端機按下 Ctrl+C,context 被取消,就會進一步呼叫 srv.Shutdown,試著以優雅的方式把 HTTP server 關掉。整個結構沒有特別複雜,但足夠完整,讓我在未來要加上日誌、metrics 或是健康檢查時,都有地方可以安放。

實際的 main 函式長得大概是這樣,整個啟動流程都收斂在一起,讀起來也很直覺:

func main() {
	loadEnv()

	ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
	defer cancel()

	botClient := newBot()

	go botClient.StartWebhook(ctx)

	mux := newMux(botClient)

	srv := newServer(mux)

	startServer(ctx, srv)
}

整個 main 只做幾件事:先載入環境變數,建立會在 Ctrl+C 時結束的 context,初始化 Telegram bot client,啟動 Webhook,建立路由與 HTTP server,最後交給 startServer 去負責整個服務的生命週期。其他像是 loadEnvnewBotnewMuxnewServer 等邏輯,則各自拆成小函式放在檔案裡,讓程式碼在視覺與心智負擔上都比較輕盈。

環境變數與設定檔

這個專案仰賴的環境變數其實不多,卻串起了整條路徑。TELEGRAM_BOT_TOKEN 來自 Telegram 的 @BotFather,是整個 bot 身分的根本。TELEGRAM_WEBHOOK_SECRET_TOKEN 則是用來驗證 Webhook 請求,用來增加一層安全性。最後的 WEBHOOK_BASE_URL 則代表整個服務對外的 base URL。當 /set-webhook 這個路由被呼叫時,程式會讀取這個 base URL,把尾端多餘的斜線去掉,然後在後面接上 /telegram/webhook,組合出要傳給 Telegram 的完整 Webhook URL。

如果 WEBHOOK_BASE_URL 沒有設定,程式會退回到預設值 http://localhost:8000。這個設計可以讓我在本機測試時比較方便,當然在正式部署到雲端時,還是會明確地把這個變數設成實際的服務網址。

在本機與雲端跑起來的樣子

當我在本機啟動 go-bot 時,它其實就和一個普通的 Go HTTP 服務沒有太大差別。打開瀏覽器連到 http://localhost:8000/,看到 Hello World 的那一刻,會很自然地感覺到「這個世界又多了一個用 Go 寫的小服務」。真正有趣的部分,是當我把 Webhook 設定好之後,在 Telegram 裡對著自己的 bot 打一句話,例如 Hello from Go,幾乎在同一時間,手機螢幕上就會出現一行新的訊息,上面寫著 Echo: Hello from Go。那個瞬間會很直覺地意識到:這個小專案已經不再只是一段在終端機裡跑來跑去的程式碼,而是一個能夠和真實世界互動的東西。

之後我把這個服務部署到雲端。部署的過程和一般 Go 應用沒有太大差別,重點就是確保環境變數都在服務端正確設定,包括 TELEGRAM_BOT_TOKENTELEGRAM_WEBHOOK_SECRET_TOKENWEBHOOK_BASE_URL。服務啟動後,只要在瀏覽器裡打開對應的 /set-webhook 路徑,讓程式幫忙呼叫 Telegram 的 setWebhook API,整個系統就算正式上線了。從那一刻開始,就算關掉本機,這隻 bot 依然會安靜地在雲端替你收訊息、回訊息。

Handler 作為未來擴充的入口

目前的 handler 只是做 Echo,非常單純,但也因為這樣,它成為一個很好的起點。只要願意,隨時可以在裡面加上更多分支,處理像是 /start/help 這種指令,或者根據不同關鍵字觸發不同行為。也可以根據使用者、群組、時間等條件,做出更細膩的情境回應。對我來說,這個 handler 就像一個門,一開始只開了一條最簡單的通道,但整個架構已經準備好,等著未來的自己慢慢在上面堆東西。

現在的實作大概是這個樣子:

func handler(ctx context.Context, b *bot.Bot, update *models.Update) {
	if update.Message == nil {
		return
	}
	fmt.Println("Received update: ", update.Message.Text)

	b.SendMessage(ctx, &bot.SendMessageParams{
		ChatID: update.Message.Chat.ID,
		Text:   "Echo: " + update.Message.Text,
	})
}

一開始會先檢查這次的 Update 裡有沒有 Message,如果沒有就直接 return,避免處理不必要的事件。接著把收到的文字印在 log 裡,最後透過 SendMessage 回到同一個聊天空間,前面加上 Echo: 作為簡單的回應。未來如果要加上指令系統,只要從這裡開始往內拆邏輯就好,不需要動到底層的 Webhook 或 HTTP server 設定。

小結:一個用新技術完成的小里程碑

回頭看 go-bot 這個專案,它的功能其實不複雜,整個程式碼量也不算多,卻完整涵蓋了我想要練習的一切:用 Go 建立 HTTP 服務、處理環境變數與設定檔、透過第三方 SDK 串接 Telegram,再把這個服務部署到雲端,變成一個真正「在線上的」聊天機器人。對我來說,用 Go 做 chatbot 是一個非常剛好的實戰範例,既不會大到難以下手,又足夠讓人感受到從零到一的成就感。

接下來要怎麼長,其實就不再是「能不能做到」的問題,而是「想像力能走到哪裡」的選擇。go-bot 已經把基礎打好:它可以安全地接收訊息、穩定地回應、持續在雲端運作,隨時可以接上新的指令、串更多外部服務,甚至變成真正融入日常流程的工具。只要還有想像,總能找到更好的解法,把這個小小的 chatbot 推向下一個階段。對我來說,這不是一個畫下句點的專案,而是一個很清楚的逗點 —— 之後每一次想用 Go 試驗新點子、想把某個「也許可以這樣做」變成現實時,都可以從這裡出發,讓這隻 bot 和自己一起長大。

後端開發 Go Telegram Bot Side Project
關於 Calpa

Calpa 擅長使用 TypeScriptReact.jsVue.js 建立 Responsive Website。

他積極參與開源社區,曾在 2019 年的香港開源大會上擔任講者,提供工作經驗和見解。此外,他也在 GitHub 上公開分享個人博客程式碼,已獲得超過 300 顆星星和 60 個分支的支持。

他熱愛學習新技術,並樂意分享經驗。他相信,唯有不斷學習才能跟上快速演變的技術環境。

熱門文章

最新文章

Vibe Coding Idea Lab:AI 共創 × 靈感實作 × MVP 引爆場
精選來自超過 700 位學員、Discord 社群與線上共創活動的 idea。我們用 AI 快速落實創意,用 prompt 引爆行動,用共創測試價值。現有 ${ideas.length} 個 idea,歡迎隨緣分享。
圖片管理中心
管理圖片資源
IP 查詢
快速查詢和定位 IP 地址的地理位置和相關信息
Python 運行器
無需後端、無需登入,只需打開瀏覽器即可運行 Python 代碼(由 Pyodide 提供支持)
封面圖生成器
自動創建適合各種平台的文章封面圖
原作(青山剛昌)產生器
一鍵創建原作(青山剛昌)的封面圖
日本色彩
探索和使用傳統日本色彩
部落格內容洞察儀表板
以視覺化儀表板方式追蹤文章成效、分享熱度與分類分布,協助創作者掌握內容表現。
蒙特卡羅估算 π
使用蒙特卡羅方法演示 π 值的估算過程
LLM
使用 LLM 模型進行聊天
活動圖生成器
一鍵創建活動的封面圖
Wagmi Card
一鍵創建 Wagmi 的封面圖
Facebook Quote
Facebook Quote
Music Macro Language (MML) Studio
用程式語法編寫旋律,用音符構築想像
Blurhash
一鍵創建 Blurhash
文字分類器
使用 MediaPipe TextClassifier 分類文字
前端工程師免費工具資源
前端工程師免費工具資源
後端工程師免費工具資源
後端工程師免費工具資源
全端工程師免費工具資源
全端工程師免費工具資源
Web3 工程師免費工具資源
Web3 工程師免費工具資源
紫微斗數排盤系統|結合 AI 的命盤性格與事業財務分析生成器
紫微斗數排盤工具,輸入生日與時辰,自動生成完整命盤分析提示(Prompt)。結合最專業紫微理論與 AI 助力,助你深入解析性格、事業、財務與人際課題。免費使用,適合命理師及紫微愛好者。
PixAI Prompt 組合器|快速打造可用於 AI 繪圖的語言拼圖
使用 PixAI 卻不會寫 prompt?這個工具幫你一鍵組裝角色、表情、風格語彙,輸出高品質繪圖提示語句(Prompt),可直接貼入 PixAI 使用。適合插畫師、創作者、AI 新手與 VTuber 角色開發者。
你擁有的 .eth 是誰?一鍵查出 ENS 背後地址
只要輸入一個 ENS 名稱,我們就能幫你查出它指向哪個以太坊地址,還能看到頭像。如果你常常看到 .eth 名稱卻不知道誰在背後,這個小工具幫得上忙。
水果切割圖生成器