在開始按照本快速入門教學導覽操作之前,請確認您已完成下列其中一項操作,以確保您已取得必要的新手程式碼。新手程式碼提供了我們將用作 Messenger 體驗基礎的基本 Webhook。
我們的 Webhook 設定指南會逐步引導您如何建立首個 Webhook,以供您在按照本快速入門教學導覽操作的整個過程中使用。
建立 Webhook從 GitHub 下載我們的 Webhook 新手程式碼,並將其部署至您所選的伺服器。
下載程式碼如果您沒有伺服器可部署為 Webhook 的目的地,則可以在 Glitch 上整合運用我們的新手 Webhook 專案,為 Webhook 提供透過 HTTPS 供應的公開網址。
如要在 Glitch 上建立自己的 Webhook,請執行以下操作:
/webhook
的 Glitch 網址:
https://
在建立您的首個 Messenger 體驗之前,請先設定應用程式的憑證。
如果您尚未完成設定,請參考我們的應用程式設定指南來設定您的 Facebook 應用程式,以便在 Messenger 平台使用。
在您的應用程式經已提交並獲准在 Messenger 上公開使用之前,專頁憑證只允許您的專頁與已取得應用程式「管理員」、「開發人員」或「測試人員」角色的 Facebook 帳戶互動。
若要向其他 Facebook 帳戶授予這些角色,請前往應用程式設定的「角色」分頁。
所有傳送到 Messenger 平台 API 的要求都經過驗證,方式為在查詢字串的 access_token
參數中加入專頁級別的存取憑證。
如果沒有在設定 Facebook 應用程式時完成這項操作,請按照下列操作產生專頁存取憑證:
建議您不要將專頁存取憑證等敏感資訊透過硬式編碼的方式寫入 Webhook,以保障其安全。
如要執行此操作,請在您的環境變數中加入以下內容,其中 <PAGE_ACCESS_TOKEN>
是您剛才產生的存取憑證,<VERIFY_TOKEN>
是您設定用於驗證 Webhook 的隨機字串:
PAGE_ACCESS_TOKEN="
如果您是使用 Glitch,請在提供的 .env
檔案中設定環境變數,確保它們不為其他 Glitch 用戶所見。
現在,您只需在 app.js
檔案上加入專頁存取憑證和驗證憑證,以便在 Webhook 邏輯中使用:
const PAGE_ACCESS_TOKEN = process.env.PAGE_ACCESS_TOKEN;
const VERIFY_TOKEN = process.env.VERIFY_TOKEN;
在本教學導覽中,我們將建立一個具備下列功能的簡易 Messenger 體驗:
剖析來自傳入 webhook 事件的訊息和傳送者專頁範圍編號。
處理 messages
和 messaging_postbacks
Webhook 事件。
透過傳送 API 傳送訊息。
以文字訊息回覆其他文字訊息。
以通用範本(使用接收到的圖片)回覆圖片附件。
有條件地回覆回傳裝載。
首先,我們要刪去三個函數的餘下部分;這三個函數會處理所要支援的傳入 Webhook 事件類型,以及透過傳送 API 進行的回覆程序。若要執行此操作,請將以下項目附加至您的 app.js
檔案:
// Handles messages events
function handleMessage(sender_psid, received_message) {
}
// Handles messaging_postbacks events
function handlePostback(sender_psid, received_postback) {
}
// Sends response messages via the Send API
function callSendAPI(sender_psid, response) {
}
若要在 Messenger 上回覆別人,首先我們要知道他們的身分。在 Messenger 中,只要從傳入 Webhook 事件取得訊息傳送者的專頁範圍編號(PSID),即可知道對方的身分。
用戶與每個 Facebook 專頁展開對話時,系統都會為用戶分配一個不重複的專頁範圍編號(PSID)。PSID 用於在傳送訊息時識別用戶。
如果您已完成上文新手專案部分中的任何一個操作選項,應該就會擁有一個基本 /webhook
端點,可用來接受 POST
要求並記錄所收到 Webhook 事件的內文;如下所示:
app.post('/webhook', (req, res) => {
// Parse the request body from the POST
let body = req.body;
// Check the webhook event is from a Page subscription
if (body.object === 'page') {
// Iterate over each entry - there may be multiple if batched
body.entry.forEach(function(entry) {
// Get the webhook event. entry.messaging is an array, but
// will only ever contain one event, so we get index 0
let webhook_event = entry.messaging[0];
console.log(webhook_event);
});
// Return a '200 OK' response to all events
res.status(200).send('EVENT_RECEIVED');
} else {
// Return a '404 Not Found' if event is not from a page subscription
res.sendStatus(404);
}
});
若要取得傳送者的 PSID,請將 body.entry.forEach
區塊更新為以下程式碼,以便從事件的 sender.id
屬性擷取 PSID:
body.entry.forEach(function(entry) {
// Gets the body of the webhook event
let webhook_event = entry.messaging[0];
console.log(webhook_event);
// Get the sender PSID
let sender_psid = webhook_event.sender.id;
console.log('Sender PSID: ' + sender_psid);
});
Sender PSID: 1254938275682919
我們希望建立的體驗能夠處理兩種 Webhook 事件:messages
和 messaging_postback
。事件類型名稱不會包含在事件內文中,但我們可以透過檢查是否有特定物件屬性的方式來判斷這個名稱。
Messenger 平台會傳送 Webhook 事件,以便通知您 Messenger 中發生的操作。事件會以 JSON 格式和 POST
要求的形式傳送到 Webhook。如需更多資訊,請參閱 Webhook 事件。
若要做到這一點,請將 Webhook 的 body.entry.forEach
區塊更新為一項特定條件;該條件會檢查收到的事件是否內含 message
或 postback
屬性。此外,我們也會在先前被刪去餘下部分的 handleMessage()
和 handlePostback()
函數中加入呼叫:
body.entry.forEach(function(entry) {
// Gets the body of the webhook event
let webhook_event = entry.messaging[0];
console.log(webhook_event);
// Get the sender PSID
let sender_psid = webhook_event.sender.id;
console.log('Sender PSID: ' + sender_psid);
// Check if the event is a message or postback and
// pass the event to the appropriate handler function
if (webhook_event.message) {
handleMessage(sender_psid, webhook_event.message);
} else if (webhook_event.postback) {
handlePostback(sender_psid, webhook_event.postback);
}
});
現在傳入訊息能導向到適當的處理常式函數,我們會更新 handleMessage()
來處理並回覆基本文字訊息。為此,請更新程式碼來定義我們回覆的訊息裝載,然後將裝載傳送至 callSendAPI()
。我們希望以基本文字訊息回覆,因此會以 "text"
屬性定義 JSON 物件:
function handleMessage(sender_psid, received_message) {
let response;
// Check if the message contains text
if (received_message.text) {
// Create the payload for a basic text message
response = {
"text": `You sent the message: "${received_message.text}". Now send me an image!`
}
}
// Sends the response message
callSendAPI(sender_psid, response);
}
現在來試試用 Messenger 平台的傳送 API 來傳送訊息吧!
在 handleMessage()
中,我們呼叫的是 callSendAPI()
,因此需要將其更新,才能建構完整要求內文並將其傳送到 Messenger 平台。對傳送 API 的要求有兩個屬性:
recipient
:設定訊息傳送對象。在這種情況下,我們會以 PSID 識別用戶。message
:設定要傳送的訊息詳情。在此,我們會將其設定為從 handleMessage()
函數傳入的訊息物件。若要建構要求內文,請將 callSendAPI()
的餘下部分更新為以下內容:
function callSendAPI(sender_psid, response) {
// Construct the message body
let request_body = {
"recipient": {
"id": sender_psid
},
"message": response
}
}
現在,我們只需要在 https://graph.facebook.com/v2.6/me/messages
向傳送 API 提出 POST
要求,即可傳送訊息。
請注意,您必須在網址查詢字串的 access_token
參數中附加 PAGE_ACCESS_TOKEN
。
在本快速入門指南中,我們使用 Node.js 要求模組來向 Messenger 平台傳回 HTTP 要求,但您可以隨意使用其他 HTTP 用戶端。
若要安裝要求模組,請在指令行中執行 npm install request --save
,然後在 app.js
上方新增下列內容以將其匯入:
const request = require('request');
function callSendAPI(sender_psid, response) {
// Construct the message body
let request_body = {
"recipient": {
"id": sender_psid
},
"message": response
}
// Send the HTTP request to the Messenger Platform
request({
"uri": "https://graph.facebook.com/v2.6/me/messages",
"qs": { "access_token": process.env.PAGE_ACCESS_TOKEN },
"method": "POST",
"json": request_body
}, (err, res, body) => {
if (!err) {
console.log('message sent!')
} else {
console.error("Unable to send message:" + err);
}
});
}
由於我們的回應會提示訊息傳送對象傳送圖片,所以我們的下一步便是更新程式碼來處理附件。已傳送的附件會自動由 Messenger 平台儲存,並透過 attachments
陣列中每個索引 payload.url
屬性的網址來顯示,因此我們也會從事件擷取這個網址。
若要判斷訊息是否為附件,請更新 handleMessage()
函數的條件,以檢查 attachments
屬性的 received_message
,然後擷取其網址。在現實生活的 BOT(機械人程式)中,我們會反覆處理陣列來檢查是否有多個附件;但就本快速入門而言,我們只會取得第一個附件。
function handleMessage(sender_psid, received_message) {
let response;
// Checks if the message contains text
if (received_message.text) {
// Creates the payload for a basic text message, which
// will be added to the body of our request to the Send API
response = {
"text": `You sent the message: "${received_message.text}". Now send me an attachment!`
}
} else if (received_message.attachments) {
// Gets the URL of the message attachment
let attachment_url = received_message.attachments[0].payload.url;
}
// Sends the response message
callSendAPI(sender_psid, response);
}
接下來,我們會以通用範本訊息來回覆圖片。通用範本是最常用的結構化訊息類型,可讓您在單一訊息中傳送圖片、文字和按鈕。
訊息範本是在訊息的 attachment
的屬性中定義,此屬性內含 type
和 payload
屬性。透過 payload
,我們可以在下列屬性中設定通用範本的詳細資料:
template_type
:設定訊息所用範本的類型。我們使用的是通用範本,因此值是「generic」。elements
:設定範本的自訂屬性。對於通用範本,我們會指定標題、副標題、圖片,以及兩個回傳按鈕。對於結構化訊息,我們會使用傳送給我們作為 image_url
的 attachment_url
來顯示在範本中,並加入兩個回傳按鈕來允許訊息傳送對象回覆。若要建構訊息裝載並傳送通用範本,請將 handleMessage()
更新為以下內容:
function handleMessage(sender_psid, received_message) {
let response;
// Checks if the message contains text
if (received_message.text) {
// Create the payload for a basic text message, which
// will be added to the body of our request to the Send API
response = {
"text": `You sent the message: "${received_message.text}". Now send me an attachment!`
}
} else if (received_message.attachments) {
// Get the URL of the message attachment
let attachment_url = received_message.attachments[0].payload.url;
response = {
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"elements": [{
"title": "Is this the right picture?",
"subtitle": "Tap a button to answer.",
"image_url": attachment_url,
"buttons": [
{
"type": "postback",
"title": "Yes!",
"payload": "yes",
},
{
"type": "postback",
"title": "No!",
"payload": "no",
}
],
}]
}
}
}
}
// Send the response message
callSendAPI(sender_psid, response);
}
最後一步是處理 messaging_postbacks
Webhook 事件,當訊息傳送對象點按通用範本中的其中一個回傳按鈕時,系統就會傳送這個事件。
回傳按鈕會傳送 messaging_postbacks
Webhook 事件到您的 Webhook,內含一個在 payload
屬性中由最多 1,000 個字元所組成的自訂字串。這樣您就能輕鬆執行各種回傳裝載,然後加以剖析並以特定行為回覆。
由於通用範本可讓訊息傳送對象從兩個回傳按鈕中擇一使用,因此我們會根據回傳事件 payload
屬性的值來回覆。若要做到這一點,請將您 handlePostback()
的餘下部分更新為以下內容:
function handlePostback(sender_psid, received_postback) {
let response;
// Get the payload for the postback
let payload = received_postback.payload;
// Set the response based on the postback payload
if (payload === 'yes') {
response = { "text": "Thanks!" }
} else if (payload === 'no') {
response = { "text": "Oops, try sending another image." }
}
// Send the message to acknowledge the postback
callSendAPI(sender_psid, response);
}