在开始此快速入门之前,请确保您已完成以下其中一项操作,以确保您拥有所需的入门代码。入门代码提供了基本的 Webhooks,我们会将其用作 Messenger 体验的基础。
我们的 Webhooks 设置指南将引导您构建自己的首个 Webhooks,供您在此快速入门的全程使用。
构建您的 Webhooks从 GitHub 下载我们的 Webhooks 入门代码,并将其部署到您选择的服务器上。
下载代码如果您没有用于部署 Webhooks 的服务器,则可以在 Glitch 上整合我们的入门 Webhooks 项目,为 Webhooks 提供使用 HTTPS 的公共网址。
要在 Glitch 上创建自己的 Webhooks,请执行以下操作:
/webhook
的 Glitch 网址:
https://
在构建首个 Messenger 体验之前,请先为您的应用设置凭证。
如果您还未设置,请按照我们的应用设置指南设置您的 Facebook 应用,以与 Messenger 开放平台配合使用。
在您的应用经过提交并获准在 Messenger 上公开使用之前,公共主页口令仅允许您的公共主页与已被授予应用管理员、开发者或测试者身份的 Facebook 帐户进行互动。
要将这些身份授予其他 Facebook 帐户,请前往应用设置的“身份”选项卡。
针对 Messenger 开放平台 API 的所有请求的验证方式为在查询字符串的 access_token
参数中添加公共主页层级访问口令。
如果您在设置 Facebook 应用时尚未完成这一步,请执行以下操作来生成公共主页访问口令:
建议您不要将敏感信息(例如公共主页访问口令)硬编码到 Webhooks 中,以确保其安全。
为此,请将以下内容添加到您的环境变量中,其中 <PAGE_ACCESS_TOKEN>
是您刚刚生成的访问口令,而 <VERIFY_TOKEN>
是您设置用于验证 Webhooks 的随机字符串:
PAGE_ACCESS_TOKEN="
如果您使用 Glitch,请在提供的 .env
文件中设置您的环境变量,以确保其他 Glitch 用户无法看到。
现在您所要做的就是在 app.js
文件的顶部添加并验证公共主页访问口令,以便在 Webhooks 逻辑中使用:
const PAGE_ACCESS_TOKEN = process.env.PAGE_ACCESS_TOKEN;
const VERIFY_TOKEN = process.env.VERIFY_TOKEN;
在本教程中,我们将构建一个用以完成以下操作的简单 Messenger 体验:
从传入的 Webhooks 事件中解析消息和发送者的公共主页范围编号。
处理 messages
和 messaging_postbacks
Webhooks 事件。
通过发送 API 发送消息。
用文本消息回复文本消息。
用使用所接收图像的通用模板回复图像附件。
有条件地响应回传负载。
首先,我们将存根三个函数,这些函数会处理我们想要支持的传入 Webhooks 事件类型,以及通过发送 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 中,这通过从传入 Webhooks 事件中获取消息发送者的公共主页范围编号 (PSID) 来实现。
系统针对用户展开对话的每个 Facebook 公共主页,为用户分配了唯一公共主页范围编号 (PSID)。PSID 用于在发送消息时识别用户。
如果您完成了上面入门项目部分中的任一选项,您应该已获得一个基本 /webhook
端点,这个端点可接受 POST
请求并记录所接收 Webhooks 事件的主体,如下所示:
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
我们希望体验能够处理两种类型的 Webhooks 事件:messages
和 messaging_postback
。事件类型的名称不包含在事件主体中,但我们可以通过检查特定对象属性来确定名称。
Messenger 开放平台发送 Webhooks 事件以通知您 Messenger 中发生的操作。系统会将事件作为 POST
请求,以 JSON 格式发送至您的 Webhooks。详情请参阅 Webhooks 事件。
为此,请使用检查所接收事件是否包含 body.entry.forEach
或 message
属性的条件更新 Webhooks 的 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 请求模块将 HTTP 请求发回 Messenger 开放平台,但您可以使用自己喜欢的任何 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()
函数中的条件,检查 received_message
是否具有 attachments
属性,然后提取其网址。在实际的智能助手中,我们将迭代数组以检查多个附件,但在本快速入门中,我们将只获取第一个附件。
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
:设置模板的自定义属性。对于通用模板,我们将指定标题、副标题、图像和两个回传按钮。对于结构化消息,我们将使用发送给我们的 attachment_url
作为在模板中显示的 image_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
Webhooks 事件,该事件将在消息接收者轻触我们通用模板中的其中一个回传按钮时发送。
回传按钮向您的 Webhooks 发送一个 messaging_postbacks
Webhooks 事件,该事件的 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);
}