Telegram Bot機器人申請與Webhook指令全紀錄

隨著高度爭議的LINE 2.0收費機制全面實施後,社會有一股力量慢慢地往免費的Telegram來推移,但我認為這樣的運動是沒有意義的,一來天下沒有永遠免費的午餐,二來現代化社會賦予給即時通訊軟體24小時溝通的本質,不會因為換了品牌而有所改變。想想看,就算Telegram永遠維持免費讓你無限發送訊息,那對手機使用者本身來說,這個環境是好還是不好?這問題或許永遠沒有標準答案(視應用場合而定),但就LINE對於發訊量的縮減政策,我相信他們與我想到的是同一件事情。

說了這麼多的引言只是發發牢騷,不代表我喜歡LINE這個軟體,事實上我非常討厭LINE。話不多說了,開始正題。

申請Telegram機器人與發送訊息

Step 1. 申請一個Telegram帳號。

Step 2. 加入@BotFather為好友,對他輸入指令「/newBot」,假設機器人顯性ID為「@MyBot」,注意機器人的名稱可以不用Bot結尾,但@帳號最後一定是Bot結尾。

Step 3. @BotFather會給你一組機器人的AccessToken(假設:123456:ABCDEF-1234),這組序號千萬要保存好,如果外流就糟糕了。

Step 4. 建立一個Public Channel,假設名為「@MyTesting」,並將機器人「@MyBot」加入為Administrators。

Step 5. 利用HTTP GET方法進行第一次送訊,並請透過返回訊息觀察JSON中的result>chat>id,這代表這個Channel的編號(假設:-65535):

https://api.telegram.org/bot123456:ABCDEF-1234/sendMessage?chat_id=@MyTesting&text=HelloWorldByReadableChatId

Step 6. 基於安全與隱私,建議將Channel設定為Private尤佳,但是當Channel變成Private後上列第五步驟的chat_id就不能填上「公開實名」名稱了,必須使用「數字型態」的chat_id,例如:

https://api.telegram.org/bot123456:ABCDEF-1234/sendMessage?chat_id=-65535&text=HelloWorldByNumericChatId

貼心小提示

無論是Channel或是Group,只要屬性是Public,都可透過「t.me/你的自訂名稱」使用GET型態的sendMessage發送訊息。例如下列指令:

https://api.telegram.org/Bot{你的Token}/sendMessage?chat_id=@{你的自訂名稱}}&text={你的文字}

若你覺得改成Private還是可以傳送?那是因為Telegram伺服器的設定延遲,過個一分鐘後你再測試就會得到:

{
  "ok": false,
  "error_code": 400,
  "description": "Bad Request: chat not found"
}

基本上若要使用Telegram Bot機器人,還是建議使用「數字型態的chat.id」回送會比較相容,因為無論Public或Private都可以接受這個格式。


申請Telegram Bot Webhook,讓訊息遞送到你建立的程式碼處理

其實Telegram Bot遞送訊息的通道有兩種,一種叫做getUpdates(Telegram Bot被動)另外一種叫Webhook(Telegram Bot主動)。getUpdates你必須主動的去Telegram API詢問現在有沒有指令或訊息,以現代的技術上來說不必要、負擔太大,也不太即時,使用的人應該很少才對。所以我們的重點會放在Webhook首,先先看一下建立、查看、刪除Webhook的相關指令列表:

//Set Webhook
https://api.telegram.org/bot123456:ABCDEF-1234/setWebhook?url=https://你的DomainName/你的程式路徑
{
  "ok": true,
  "result": true,
  "description": "Webhook was set"
}
//Delete(Remove) Webhook
https://api.telegram.org/bot123456:ABCDEF-1234/deleteWebhook
{
  "ok": true,
  "result": true,
  "description": "Webhook was deleted"
}
//Get Webhook Information
https://api.telegram.org/bot123456:ABCDEF-1234/getWebhookInfo
{
  "ok": true,
  "result": {
    "url": "",
    "has_custom_certificate": false,
    "pending_update_count": 0
  }
}

你可以在getWebhookInfo中的JSON回傳看到一個叫做pending_update_count的屬性,這個的意思是指目前機器人收到的指令中,未處理的訊息有多少個。Telegram Bot Webhook有一個很有趣的實作,就是當你的伺服器傳回非200的HTTP response status codes,他會反覆的敲門喔!所以我建議大家在寫程式發生未預期的錯誤時盡量拋出Http 200 OK,不然你可能會被不斷敲門喔!

若真的有需要清除pending_update_count,可以手動呼叫一次getUpdates,我想拿回來什麼都不做,就是一種清除吧!

https://api.telegram.org/bot123456:ABCDEF-1234/getUpdates

Telegram的Channel、Group與Bot Webhook之間的關係

⭐ Channel 頻道:

  1. Channel可以LINK既有Group或建立新Group,當有人(包含Bot)在Channel發言時,所有被LINK到的Group都會出現相同的訊息。
  2. Channel在意義上比較像是公有頻道、廣播頻道,適合被拿來做單向通知。
  3. 在Channel裡面發送的所有訊息,Bot都看得到也就是會觸發Webhook。(因為在Channel內的Bot身分強制是Administrators)

⭐ Group 群組:

  1. Group在意義上比較像是討論群組,大夥在群組裡面私聊講些五四三的。
  2. 在Group裡面發送的所有訊息除非前面加上「\」符號,否則Bot看不到也就是不觸發Webhook。(除非特別設定)
  3. 要特別設定Bot可以看到群組裡面的每一句話(不需要加上「\」符號),就要請BotFather出來把「can_read_all_group_messages」選項設定為true。(跟BotFather講「/setprivacy」後,會有UI引導操作)

BOT 隱私知識

  1. 預設所有的Bot的privacy mode都是被Enabled的。
  2. 但如果該隻Bot的身分是Administrators,那麼他預設就看的到所有的訊息。(不需要加上「\」符號)

觀察Bot是否能夠讀取群組的每一句訊息,可輸入下面指令:

https://api.telegram.org/bot123456:ABCDEF-1234/getMe
{
  "ok": true,
  "result": {
    "id": 123456,
    "is_Bot": true,
    "first_name": "OOO",
    "username": "OOOBot",
    "can_join_groups": true,
    "can_read_all_group_messages": false, //true 代表可到群組內所有訊息
    "supports_inline_queries": false
  }
}

Telegramt Bot Webhook於Personal、Channel、Group傳入訊息JSON格式列表

對Bot私聊:

{
  "update_id":7878978,
  "message":{
    "message_id":78,
    "from":{
      "id":個人代表ID,
      "is_Bot":false,
      "first_name":"你的名字",
      "username":"你的代號",
      "language_code":"zh-hans"
    },
    "chat":{
      "id":個人代表ID,
      "first_name":"你的名字",
      "username":"你的代號",
      "type":"private"
    },
    "date":1234567890,
    "text":"我在與機器人一對一聊天"
  }
}

對Group群聊:

{
  "update_id":7878978,
  "message":{
    "message_id":78,
    "from":{
      "id":個人代表ID,
      "is_Bot":false,
      "first_name":"你的名字",
      "username":"你的代號",
      "language_code":"zh-hans"
    },
    "chat":{
      "id":-0806449,
      "title":"群組名稱",
      "type":"group",
      "all_members_are_administrators":true
    },
    "date":1234567890,
    "text":"/我在群組內進行群聊",
    "entities":[
      {
        "offset":0,
        "length":10,
        "type":"Bot_command"
      }
    ]
  }
}

對Channel發言:

{
  "update_id":7878978,
  "channel_post":{
    "message_id":78,
    "chat":{
      "id":-0806449,
      "title":"頻道名稱",
      "username":"頻道唯一帳號",
      "type":"channel"
    },
    "date":1234567890,
    "text":"我在對頻道進行發言"
  }
}

這三個JSON提供了一個很重要的資訊,就是chat>id可以描述出回信的目標對象,text可以取得使用者到底講了什麼。但他們分處於不一樣的父屬性下(message、channel_post),我個人認為設計的蠻爛的,畢竟都有type屬性在跟你講說現在是Channel還是Group了不是嗎?總之,有了上面三種資訊,相信聰明的你要寫出一個Telegram Bot加上Webhook應該不是太難的事情了吧!Happy Coding!

相關連結

Telegram Bot API
Bots: An introduction for developers

Telegram Bot Bots Create Set Remove Delete Webhook