Facebook Messenger Platform

[網路應用] Facebook Messenger Platform

隨著 股票賈維斯 完成了 V2 版本 的開發,針對 Messenger Platform 的心得也差不多足夠做個紀錄。這樣寫下技術的學習過程對我而言頗有意思,一方面有機會幫助到某處正在百思不得其解的人;另一方面這像是埋下一顆時空膠囊,等回過頭來看的時候那種昨是今非的感慨,又或者百般慶幸當初的自己有做過這樣的事。

不論寫過哪一家公司出的 Messenger (Bot),要再把它移植到另外一個平台基本上就不是一件難事。主要是因為 Bot 扮演著資訊橋接的角色,目的是要讓各地的有價資訊能夠方便地在平台上面被產出,本質上「內容」才是王道,Bot 頂多只能算個輔助角。而為了有效而快速的推廣,Messenger 本身的架構也就不能太複雜,初期只要提供一個基礎介面即可。所以在各大平台互相參考與競爭速度之下,架構是相當類似的。

初號機

上圖是 V1 版本的股票賈維斯,全部只套用了 3 個 API,分別是:認證用的 subscribe API、對話專屬 Message API、跟 Postback API。其中 subscribe 顧名思義就是註冊用的,確認 Bot 是在正確的主機上;Postback API 單純用在對新朋友說歡迎光臨;主角是 Message API,所有的對話邏輯都在這裡判斷。

雖然說是對話邏輯,但以投資的領域來說,股友最習慣的還是「股號」,而投資基金就是「基金名稱」,所以股票賈維斯做了最簡單的簡化:只解析使用者輸入的股號。這樣的介面說不上有智慧,但還好內容本身有價值,加上能與 StockExpress 網站結合在同一個手機畫面開啟營收圖表,這個賈維斯初號機算是堪用。

而每當我一有「XX開發還真是簡單」念頭的時候,麻煩事常常接踵而來。不久就發現 Facebook Messenger 有自動重發訊息的機制,一但 Facebook 沒有在一定時間內收到主機的 webhook 回應,它會將這個訊息過一陣子之後持續重發,同時沒有任何方式可以請求 Facebook 清空這些訊息。所以一旦主機出問題,或是網路出問題,或是程式改壞了,訊息就會開始不斷的累積… 等到問題解決,所有累積的訊息就是脫韁野馬… 萬馬奔騰簡直最棒形容。最終你會看到粉絲團對話紀錄,很多人的未讀訊息數量是 99 XD

一旦發現問題,請立刻到 Facebook developer 後台把粉絲團的 subscribe 取消。這是避免訊息泡沫的方式。

隔離實驗室

由於 FB Messenger 沒有 sandbox 環境可以測試,導致軟體開發很難偵錯,初期幾乎是用線上環境直接測試程式碼,風險很高。一直到後期 V1 微調跟改建 V2 版本股票賈維斯,才導入超級好用的 ngrok。上圖稍微說明了 ngrok 的原理,即使你被防火牆保護或是在 NAT 網路,都可以讓開發機能透過 ngrok 被外部網路存取。最棒的是可以產生一個動態的 https 安全連線網域,如此一來在開發階段就能直接串 Facebook Webhook,完成前一段提到的 subscribe API 流程。

而目前找到最佳的程式部署方式,就是在上傳新版本之前,使用 ngrok 將 Messenger subscription 指向到自己的開發機,同時提示使用者目前 Bot 正在改版中。此時就可以利用開發機快速測試、除錯、調整,當所有新功能或是補丁在開發機確認完畢,再將 subscription 指回線上主機。

另外,在 ngrok 切換環境之前多寫一點 Unit Test ,優先先確保每一區塊邏輯運行正確也不失為加速新版本上線的好方法。

優雅的步伐

以前的我喜歡跟著感覺走,想到什麼功能就做什麼功能,所以常常無止境的一個接一個工作,把自己弄得太累;不喜歡現在畫面就捲起袖子直接調整,然後牽一髮而動全身搞得心情烏煙瘴氣。

才發現,有計劃的革新是一件好事。

賈維斯進化 這一篇把 V2 改版的重點都事先記錄下來,在開發 V2 的過程中,一邊看著文章一編寫 code 感覺踏實。好像小時候的著色遊戲,把眼前的輪廓用色彩裝飾成鮮明的圖畫。上圖是依照計畫寫完的成果圖,完全符合規劃!完成後就告一段落,接著休息、充電, 好好準備下一次,因為又有使用者提出好功能建議啦,別讓粉絲等太久~ 🙂

還沒跟股票賈維斯聊過天?按這裡速聊

您可能也會喜歡…

7 個回應

  1. Wilson Huang Wilson Huang 說:

    ngrok 是個好解法欸!之前都沒想到!

  2. Louis Liu Louis Liu 說:

    Hsuan-Hao Chan 很厲害耶!

  3. 只有學長可以寫程式也寫得這麼浪漫

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *