接下來幾天會介紹怎麼把前幾天在 Console Mode 做的機器人搬上像是 Messenger、LINE 這些台灣人常在使用的管道。
而今天的目標會放在 Messenger 上,首先我們要先修改之前只支援使用 Console Mode 的設定檔:
bottender.config.js
設定檔在 bottender.config.js
的設定檔裡面需要新增 messenger
的設定在 channels
裡面:
// bottender.config.js
require('dotenv').config(); // 記得 npm install dotenv
module.exports = {
//... 其他省略
channels: {
messenger: {
enabled: true,
path: '/',
pageId: process.env.MESSENGER_PAGE_ID,
accessToken: process.env.MESSENGER_ACCESS_TOKEN,
verifyToken: process.env.MESSENGER_VERIFY_TOKEN,
appId: process.env.MESSENGER_APP_ID,
appSecret: process.env.MESSENGER_APP_SECRET,
},
},
};
這邊我們都是使用 process.env
(環境變數) 來避免直接把敏感資訊的字串寫在程式碼裡面,這是一個好習慣,除了可以輕易地在不修改程式的情況下改設定,更可以避免輕易的把 Commit 到 Git 裡面去,或甚至因此上傳到網路、GitHub 上。
最上方的 require('dotenv').config()
,是我們打算使用 dotenv 這個套件,來直接讀取 .env
這個檔案的設定注入到 process.env
,所以這些敏感的資料我們需要另外建立 .env
檔案來放:
// .env
MESSENGER_PAGE_ID=
MESSENGER_ACCESS_TOKEN=
MESSENGER_VERIFY_TOKEN=
MESSENGER_APP_ID=
MESSENGER_APP_SECRET=
(注意:如果有在用 Git,這個 .env
必須列在 .gitignore
裡面)
從這邊可以看到,我們需要五個環境變數設定:
這些東西還不用馬上填,都將在下一個步驟 - 「建立 Facebook 應用程式」之後來填入。
如果你已經很熟悉怎麼建立 Facebook 應用程式,可以直接跳過這段教學,直接填好 .env
並從下一段「建立 Webhook 開始」。
為了建立 Facebook 應用程式,我們必須到 Facebook Developer 的網頁 - http://developers.facebook.com,然後點擊「我的應用程式」> 「建立應用程式」:
建立一個新的應用程式後,要來新增 Messenger 相關的設定,所以要點擊 Messenger 的「設定」按鈕:
跳轉頁面後接著頁面往下滑,可以看到「新增或移除粉絲專頁」,點他新增專頁:
(沒有粉絲專頁則要先建立新的粉絲專頁)
授權好了之後,會看到這樣的畫面會有「Page Id」,必須填到你的 .env
檔案裡面的 MESSENGER_PAGE_ID
欄位,接著要點「產生權杖」:
產生出來這個複製出來就是「Access Token」,必須填到你的 .env
檔案裡面的 MESSENGER_ACCESS_TOKEN
欄位:
Menu「設定」進去「基本資料」那邊則可以拿到「App Id」以及「App Secret」,分別填到你的 .env
檔案裡面的 MESSENGER_APP_ID
以及 MESSENGER_APP_SECRET
欄位:
// .env
MESSENGER_PAGE_ID=你的 Page Id
MESSENGER_ACCESS_TOKEN=你的 Access Token
MESSENGER_VERIFY_TOKEN=1Q40y4m1U0t05CL
MESSENGER_APP_ID=你的 App Id
MESSENGER_APP_SECRET=你的 App Secret
至於 MESSENGER_VERIFY_TOKEN 可以隨便填一段字或是學我在 Strong Password Generator 上面產生一段比較安全的。
這樣就收集完 Facebook 這邊需要的資料囉!
當我們按照前面的教學,把 bottender.config.js
加上 channels.messenger
的設定時,這時候執行 bottender dev
將會自動地開啟 Server,並使用 ngrok 產生一個對外的 HTTPS 網址。
npx bottender dev
(注意:這次就不要加 --console
了)
為什麼需要 ngrok 呢?
因為當我們開發時在自己電腦上開啟 Server 時,我們能透過 http://localhost:port
去連到,但這樣子 Facebook 是無法連到我們的 Server 的,所以需要開 Tunnel,而且他們還能提供 Secure 的 HTTPS 連線。
這樣子的服務、工具,最有名的就是以下幾個:
在打開 ngrok 的情況下,前往 http://localhost:4040
應該能看到它的 Inspector:
這可以用來檢查 Facebook 是否有送東西過來我們的 Server。
開好了 Server 跟 ngrok 後要另外用另一個 Terminal 分頁來執行以下指令:
npx bottender messenger webhook set
這邊會從你的 bottender.config.js
把一些資訊拉出來,並把網址從 ngrok 找到,送去給 Facebook 訂閱相關事件送到 Webhook。
最後在 Messenger 上測試一下 Bot:
是不是很熟悉?這就是我們前兩天做的笑話機器人跟比特幣機器人喔。
不管是接什麼平台,這開應用程式跟設定的步驟總是最煩瑣而且又容易出錯,不過馬上就要苦盡甘來了,最難的就是這個了。
請問一下,當我想開啟 ngrok 時遇到這個 error
PS. 目前步驟已填完 .env 那些KEY
目前還沒遇過這個狀況,這樣資訊還不太夠
不好意思有沒有可能提供一下更詳細的重現步驟或 Repo,讓我們有辦法 Debug 這個部分呢?
我直接下載 ngrok 測試,發現應該是我本機連不到 ngrok server 造成 timeout 所導致
不好意思! 又來打擾
目前
但最後一步,從 Messager 傳訊息給 BOT
BOT 卻沒收到 request
請問還有哪些地方要設定呢 (?
附上過程圖
[ngrok 開啟成功]
[webhook 設定成功]
最常見的狀況可能是沒聽到對應的 event,可以檢查一下這裡
MESSENGER_PAGE_ID 有填到理論上應該要自動設定,這個部分有填嗎?(另外想問一下 bottender 的版號)
這邊有
bottender 版本
這樣看起來很正常,收不到蠻奇怪的
另外一個我懷疑的是 Primary Receiver 的設定有沒有異常,有時候如果這個粉絲頁曾經綁過其他 App 會出一點問題
可以參考這篇檢查一下這個設定:
https://ithelp.ithome.com.tw/articles/10220717#response-312610
感謝 !! 我晚上回去試試
設定完後,可以在 ngrok 那邊看到 POST 200 成功
但訊息依舊直接進入 inbox
不好意思! 提個問題,想要看到 BOT 回應訊息
一定要用粉絲專頁的"管理員"
自己傳訊息到自己的紛絲專頁嗎 (?
我用兩個帳號測試
傳訊息 from 管理員的帳號 => 看的到 BOT 回應
傳訊息 from 一般的帳號 => 看不到 BOT 回應,訊息會直接進入 inbox
如果你的 App 尚未調成 Public 並送審權限,那就會只有管理員或是任何被你加到測試人員的人可以測試(應該可以在 App 設定某處加測試人員)
好的感謝 !!
請問一下
要把講笑話和btc放在一起是怎麼弄的
為什麼我的指顯示講話的內容
可以貼一下你的程式碼嗎?
const random = require('random-item');
const coinranking = require('../coinranking');
module.exports = async function App(context) {
if (context.event.text === '講笑話') {
await context.sendText(
random([
'加油站最怕什麼樣的員工?油腔滑調的員工',
'有一天,西瓜、榴槤、奇異果一起出去玩,結果榴槤不見了。因為榴槤忘返',
'海記憶體知己,天涯若比鄰',
])
);
} else {
await context.sendText(random(['你講什麼鬼話?', '乖,聊聊別的']));
}
};
const coins = [
{
id: 1,
symbol: 'BTC',
name: 'Bitcoin',
},
{
id: 2,
symbol: 'ETH',
name: 'Ethereum',
},
{
id: 3,
symbol: 'XRP',
name: 'XRP',
},
];
module.exports = async function App(context) {
const { text } = context.event;
for (let c of coins) {
if (new RegExp(`(${c.symbol})|(${c.name})`, 'i').test(text)) {
const {
data: { coin },
} = await coinranking.getCoin(c.id);
await context.sendText(`${c.symbol} 現在價格是 ${coin.price} TWD`);
return;
}
}
};
我是不是寫錯地方
我搞定了哈哈抱歉,就把方法一樣寫在裡面就好了!
不好意思剛剛使用這個框架有點不習慣QQ