Learning Objectives
- 說明 reply token 的規則,並判斷 Invalid reply token 的原因
- 用 push_message、multicast、broadcast 主動傳訊息給使用者
- 說明為什麼機器人要先存下 userId 才能主動傳訊息
- 說明 reply 與 push 類訊息對額度的影響,並提供使用者取消通知的方式
回覆一定要有事件,通知不一定有
前幾課的機器人都是「收到才回」。如果老師要通知全班明天停課,這時候沒有人傳訊息,也就沒有事件可以回覆。Messaging API 因此有兩類傳送方式:
| 回覆(reply) | 主動傳送(push、multicast、broadcast) | |
|---|---|---|
| 什麼時候用 | 收到事件之後 | 任何時候 |
| 要準備什麼 | 事件帶來的 reply token | 對方的 userId(broadcast 不用) |
| 計入額度 | 不計入 | 計入 |
這一課先看 reply token 的限制,因為它決定了什麼情況不得不改用 push。
逐步看:reply token 什麼時候失效
三句話對應三種情況:正常回覆、同一個 token 用兩次、等太久才回覆。注意輸出區哪些訊息真的送到了。
reply token 的規則
官方文件對 reply token 的規定:
- 只能用一次。
- 要在收到 webhook 後一分鐘內使用。 官方的說法是超過一分鐘「不保證可用」,而且這個時限可能不經通知就變動,所以文件要求盡快使用,不要依賴這個時限。模擬平台把超過一分鐘一律視為失效。
一次要回多則訊息時,把它們放進同一個 messages 串列(上一課),不要呼叫兩次 reply_message。
下面的機器人把回覆拆成兩步:先記下 reply token,等助教在網站上按按鈕才回覆。這種設計在真實情境很常見,也很容易踩到上面的限制。「助教回答」按鈕呼叫的是機器人自己的路由 /answer,不是 LINE 送來的 webhook。
主動傳訊息要先有 userId
push_message 不需要 reply token,但要指定收件人 to。userId 不是使用者在 LINE 上設定的 ID,也不是姓名,通常要從這個使用者傳來的事件取得(event.source.user_id),所以想主動通知的機器人,要在使用者傳訊息或加好友時把 userId 存下來。
| API | SDK 寫法 | 收件人 |
|---|---|---|
| Push | api.push_message(PushMessageRequest(to=uid, messages=[...])) |
一位 |
| Multicast | api.multicast(MulticastRequest(to=[uid1, uid2], messages=[...])) |
指定的多位 |
| Broadcast | api.broadcast(BroadcastRequest(messages=[...])) |
所有好友 |
官方還有 narrowcast,可以依條件(例如地區)篩選對象,這門課不會用到。
通知全班時,multicast 比一個一個 push_message 好:只要呼叫一次 API。to 不可以是空串列,也有人數上限,要傳給很多人時得分批,上限以官方文件為準。
逐步看:三種主動傳送與額度
兩位使用者先傳訊息訂閱,老師再用三種方式發通知。看每一行輸出最後的額度數字怎麼變化,並注意最後有人封鎖機器人之後的結果。
額度與尊重使用者
官方的計價說明規定:
- reply 不計入;push、multicast、broadcast(以及 narrowcast)計入
- 計算方式是收件人數。一次請求放幾個訊息物件不影響計數,傳給 5 個人就算 5 則
- 傳給封鎖你的使用者或不存在的 userId,不計入
每個月能傳多少、超過要不要付費,依方案而定,也可能調整,請看官方頁面。額度用完時 API 回 429。所以能用 reply 就用 reply,機器人回答問題時不要改用 push。
額度之外,還要考慮收訊息的人。 主動傳來的訊息會打斷對方,傳得太頻繁,最直接的結果就是被封鎖。設計通知功能時可以這樣做:
- 使用者自己選擇訂閱,並且隨時能取消,就像剛才做的
- 只傳對方需要知道的內容,不要因為能傳就傳
- 不急的通知可以設
notification_disabled=True,訊息照樣送達,但手機不發出提醒 - 收到
UnfollowEvent時把對方從名單移除 - 不要在紀錄裡印出完整的 userId,它是可以識別個人的資料
動手做:用 multicast 發公告
完成 announce():
- 從 JSON 取出
text - 有人訂閱時,用一次
multicast傳給subscribers - 沒有人訂閱時不呼叫 API(
to是空串列時 SDK 會丟出例外) - 兩種情況都回傳
jsonify(sent=人數)
想一想
機器人收到問題後呼叫外部服務,花了兩分鐘才準備好答案,直接用原本的 reply token 回覆,最可能發生什麼?
老師用 multicast 一次傳 2 則訊息物件給 30 位學生,官方怎麼計算額度?
機器人想在週五早上主動提醒學生交作業,事前必須做好什麼?
對封鎖機器人的使用者呼叫 push_message,結果是?
同一個事件要回「收到」和「處理完了」兩則訊息,該怎麼寫?
重點整理
- reply token 只能用一次,要在一分鐘內盡快使用;用過或過期都是
Invalid reply token - 主動傳訊息用
push_message、multicast、broadcast,前兩種要先從事件存下 userId - reply 不計入額度,其他三種依收件人數計入;封鎖的人收不到,也不計入
- API 回 200 不代表對方收到;要處理
UnfollowEvent,並讓使用者能取消通知
下一課換個方向:讓使用者不用打字。快速回覆、範本訊息與圖文選單都是按鈕,機器人也因此多了一種事件要處理。