- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我跟随 FB 的 tutorial 制作了一个 FB Messenger 机器人。 Webhook 已成功制作,我现在想要继续捕获 Facebook 用户的输入(发送到我的页面的消息),并将其用作我的 CasperJS 脚本的输入。最后,我想使用 CasperJS 脚本的输出并回复 Facebook 用户。
Facebook Messenger Bot 中使用的 app.js(基本上与示例中给出的相同,只是更改了 sendTextMessage(recipientId, messageText)
函数:
/*
* Copyright 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
*/
/* jshint node: true, devel: true */
'use strict';
const
bodyParser = require('body-parser'),
config = require('config'),
crypto = require('crypto'),
express = require('express'),
https = require('https'),
request = require('request');
var app = express();
app.set('port', process.env.PORT || 5000);
app.set('view engine', 'ejs');
app.use(bodyParser.json({ verify: verifyRequestSignature }));
app.use(express.static('public'));
/*
* Be sure to setup your config values before running this code. You can
* set them using environment variables or modifying the config file in /config.
*
*/
// App Secret can be retrieved from the App Dashboard
const APP_SECRET = (process.env.MESSENGER_APP_SECRET) ?
process.env.MESSENGER_APP_SECRET :
config.get('appSecret');
// Arbitrary value used to validate a webhook
const VALIDATION_TOKEN = (process.env.MESSENGER_VALIDATION_TOKEN) ?
(process.env.MESSENGER_VALIDATION_TOKEN) :
config.get('validationToken');
// Generate a page access token for your page from the App Dashboard
const PAGE_ACCESS_TOKEN = (process.env.MESSENGER_PAGE_ACCESS_TOKEN) ?
(process.env.MESSENGER_PAGE_ACCESS_TOKEN) :
config.get('pageAccessToken');
// URL where the app is running (include protocol). Used to point to scripts and
// assets located at this address.
const SERVER_URL = (process.env.SERVER_URL) ?
(process.env.SERVER_URL) :
config.get('serverURL');
if (!(APP_SECRET && VALIDATION_TOKEN && PAGE_ACCESS_TOKEN && SERVER_URL)) {
console.error("Missing config values");
process.exit(1);
}
/*
* Use your own validation token. Check that the token used in the Webhook
* setup is the same token used here.
*
*/
app.get('/webhook', function(req, res) {
if (req.query['hub.mode'] === 'subscribe' &&
req.query['hub.verify_token'] === VALIDATION_TOKEN) {
console.log("Validating webhook");
res.status(200).send(req.query['hub.challenge']);
} else {
console.error("Failed validation. Make sure the validation tokens match." + VALIDATION_TOKEN + ", " + req.query['hub.verify_token']);
res.sendStatus(403);
}
});
/*
* All callbacks for Messenger are POST-ed. They will be sent to the same
* webhook. Be sure to subscribe your app to your page to receive callbacks
* for your page.
* https://developers.facebook.com/docs/messenger-platform/product-overview/setup#subscribe_app
*
*/
app.post('/webhook', function (req, res) {
var data = req.body;
// Make sure this is a page subscription
if (data.object == 'page') {
// Iterate over each entry
// There may be multiple if batched
data.entry.forEach(function(pageEntry) {
var pageID = pageEntry.id;
var timeOfEvent = pageEntry.time;
// Iterate over each messaging event
pageEntry.messaging.forEach(function(messagingEvent) {
if (messagingEvent.optin) {
receivedAuthentication(messagingEvent);
} else if (messagingEvent.message) {
receivedMessage(messagingEvent);
} else if (messagingEvent.delivery) {
receivedDeliveryConfirmation(messagingEvent);
} else if (messagingEvent.postback) {
receivedPostback(messagingEvent);
} else if (messagingEvent.read) {
receivedMessageRead(messagingEvent);
} else if (messagingEvent.account_linking) {
receivedAccountLink(messagingEvent);
} else {
console.log("Webhook received unknown messagingEvent: ", messagingEvent);
}
});
});
// Assume all went well.
//
// You must send back a 200, within 20 seconds, to let us know you've
// successfully received the callback. Otherwise, the request will time out.
res.sendStatus(200);
}
});
/*
* This path is used for account linking. The account linking call-to-action
* (sendAccountLinking) is pointed to this URL.
*
*/
app.get('/authorize', function(req, res) {
var accountLinkingToken = req.query.account_linking_token;
var redirectURI = req.query.redirect_uri;
// Authorization Code should be generated per user by the developer. This will
// be passed to the Account Linking callback.
var authCode = "1234567890";
// Redirect users to this URI on successful login
var redirectURISuccess = redirectURI + "&authorization_code=" + authCode;
res.render('authorize', {
accountLinkingToken: accountLinkingToken,
redirectURI: redirectURI,
redirectURISuccess: redirectURISuccess
});
});
/*
* Verify that the callback came from Facebook. Using the App Secret from
* the App Dashboard, we can verify the signature that is sent with each
* callback in the x-hub-signature field, located in the header.
*
* https://developers.facebook.com/docs/graph-api/webhooks#setup
*
*/
function verifyRequestSignature(req, res, buf) {
var signature = req.headers["x-hub-signature"];
if (!signature) {
// For testing, let's log an error. In production, you should throw an
// error.
console.error("Couldn't validate the signature.");
} else {
var elements = signature.split('=');
var method = elements[0];
var signatureHash = elements[1];
var expectedHash = crypto.createHmac('sha1', APP_SECRET)
.update(buf)
.digest('hex');
if (signatureHash != expectedHash) {
throw new Error("Couldn't validate the request signature.");
}
}
}
/*
* Authorization Event
*
* The value for 'optin.ref' is defined in the entry point. For the "Send to
* Messenger" plugin, it is the 'data-ref' field. Read more at
* https://developers.facebook.com/docs/messenger-platform/webhook-reference/authentication
*
*/
function receivedAuthentication(event) {
var senderID = event.sender.id;
var recipientID = event.recipient.id;
var timeOfAuth = event.timestamp;
// The 'ref' field is set in the 'Send to Messenger' plugin, in the 'data-ref'
// The developer can set this to an arbitrary value to associate the
// authentication callback with the 'Send to Messenger' click event. This is
// a way to do account linking when the user clicks the 'Send to Messenger'
// plugin.
var passThroughParam = event.optin.ref;
console.log("Received authentication for user %d and page %d with pass " +
"through param '%s' at %d", senderID, recipientID, passThroughParam,
timeOfAuth);
// When an authentication is received, we'll send a message back to the sender
// to let them know it was successful.
sendTextMessage(senderID, "Authentication successful");
}
/*
* Message Event
*
* This event is called when a message is sent to your page. The 'message'
* object format can vary depending on the kind of message that was received.
* Read more at https://developers.facebook.com/docs/messenger-platform/webhook-reference/message-received
*
* For this example, we're going to echo any text that we get. If we get some
* special keywords ('button', 'generic', 'receipt'), then we'll send back
* examples of those bubbles to illustrate the special message bubbles we've
* created. If we receive a message with an attachment (image, video, audio),
* then we'll simply confirm that we've received the attachment.
*
*/
function receivedMessage(event) {
var senderID = event.sender.id;
var recipientID = event.recipient.id;
var timeOfMessage = event.timestamp;
var message = event.message;
console.log("Received message for user %d and page %d at %d with message:",
senderID, recipientID, timeOfMessage);
console.log(JSON.stringify(message));
var isEcho = message.is_echo;
var messageId = message.mid;
var appId = message.app_id;
var metadata = message.metadata;
// You may get a text or attachment but not both
var messageText = message.text;
var messageAttachments = message.attachments;
var quickReply = message.quick_reply;
if (isEcho) {
// Just logging message echoes to console
console.log("Received echo for message %s and app %d with metadata %s",
messageId, appId, metadata);
return;
} else if (quickReply) {
var quickReplyPayload = quickReply.payload;
console.log("Quick reply for message %s with payload %s",
messageId, quickReplyPayload);
sendTextMessage(senderID, "Quick reply tapped");
return;
}
if (messageText) {
// If we receive a text message, check to see if it matches any special
// keywords and send back the corresponding example. Otherwise, just echo
// the text we received.
switch (messageText) {
case 'image':
sendImageMessage(senderID);
break;
case 'gif':
sendGifMessage(senderID);
break;
case 'audio':
sendAudioMessage(senderID);
break;
case 'video':
sendVideoMessage(senderID);
break;
case 'file':
sendFileMessage(senderID);
break;
case 'button':
sendButtonMessage(senderID);
break;
case 'generic':
sendGenericMessage(senderID);
break;
case 'receipt':
sendReceiptMessage(senderID);
break;
case 'quick reply':
sendQuickReply(senderID);
break;
case 'read receipt':
sendReadReceipt(senderID);
break;
case 'typing on':
sendTypingOn(senderID);
break;
case 'typing off':
sendTypingOff(senderID);
break;
case 'account linking':
sendAccountLinking(senderID);
break;
default:
sendTextMessage(senderID, messageText);
}
} else if (messageAttachments) {
sendTextMessage(senderID, "Message with attachment received");
}
}
/*
* Delivery Confirmation Event
*
* This event is sent to confirm the delivery of a message. Read more about
* these fields at https://developers.facebook.com/docs/messenger-platform/webhook-reference/message-delivered
*
*/
function receivedDeliveryConfirmation(event) {
var senderID = event.sender.id;
var recipientID = event.recipient.id;
var delivery = event.delivery;
var messageIDs = delivery.mids;
var watermark = delivery.watermark;
var sequenceNumber = delivery.seq;
if (messageIDs) {
messageIDs.forEach(function(messageID) {
console.log("Received delivery confirmation for message ID: %s",
messageID);
});
}
console.log("All message before %d were delivered.", watermark);
}
/*
* Postback Event
*
* This event is called when a postback is tapped on a Structured Message.
* https://developers.facebook.com/docs/messenger-platform/webhook-reference/postback-received
*
*/
function receivedPostback(event) {
var senderID = event.sender.id;
var recipientID = event.recipient.id;
var timeOfPostback = event.timestamp;
// The 'payload' param is a developer-defined field which is set in a postback
// button for Structured Messages.
var payload = event.postback.payload;
console.log("Received postback for user %d and page %d with payload '%s' " +
"at %d", senderID, recipientID, payload, timeOfPostback);
// When a postback is called, we'll send a message back to the sender to
// let them know it was successful
sendTextMessage(senderID, "Postback called");
}
/*
* Message Read Event
*
* This event is called when a previously-sent message has been read.
* https://developers.facebook.com/docs/messenger-platform/webhook-reference/message-read
*
*/
function receivedMessageRead(event) {
var senderID = event.sender.id;
var recipientID = event.recipient.id;
// All messages before watermark (a timestamp) or sequence have been seen.
var watermark = event.read.watermark;
var sequenceNumber = event.read.seq;
console.log("Received message read event for watermark %d and sequence " +
"number %d", watermark, sequenceNumber);
}
/*
* Account Link Event
*
* This event is called when the Link Account or UnLink Account action has been
* tapped.
* https://developers.facebook.com/docs/messenger-platform/webhook-reference/account-linking
*
*/
function receivedAccountLink(event) {
var senderID = event.sender.id;
var recipientID = event.recipient.id;
var status = event.account_linking.status;
var authCode = event.account_linking.authorization_code;
console.log("Received account link event with for user %d with status %s " +
"and auth code %s ", senderID, status, authCode);
}
/*
* Send an image using the Send API.
*
*/
function sendImageMessage(recipientId) {
var messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "image",
payload: {
url: SERVER_URL + "/assets/rift.png"
}
}
}
};
callSendAPI(messageData);
}
/*
* Send a Gif using the Send API.
*
*/
function sendGifMessage(recipientId) {
var messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "image",
payload: {
url: SERVER_URL + "/assets/instagram_logo.gif"
}
}
}
};
callSendAPI(messageData);
}
/*
* Send audio using the Send API.
*
*/
function sendAudioMessage(recipientId) {
var messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "audio",
payload: {
url: SERVER_URL + "/assets/sample.mp3"
}
}
}
};
callSendAPI(messageData);
}
/*
* Send a video using the Send API.
*
*/
function sendVideoMessage(recipientId) {
var messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "video",
payload: {
url: SERVER_URL + "/assets/allofus480.mov"
}
}
}
};
callSendAPI(messageData);
}
/*
* Send a file using the Send API.
*
*/
function sendFileMessage(recipientId) {
var messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "file",
payload: {
url: SERVER_URL + "/assets/test.txt"
}
}
}
};
callSendAPI(messageData);
}
/*
* Send a text message using the Send API.
*
*/
function sendTextMessage(recipientId, messageText) {
var messageData = {
recipient: {
id: recipientId
},
message: {
text: "{The data fed from CasperJS}",
metadata: "DEVELOPER_DEFINED_METADATA"
}
};
callSendAPI(messageData);
}
/*
* Send a button message using the Send API.
*
*/
function sendButtonMessage(recipientId) {
var messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "template",
payload: {
template_type: "button",
text: "This is test text",
buttons:[{
type: "web_url",
url: "https://www.oculus.com/en-us/rift/",
title: "Open Web URL"
}, {
type: "postback",
title: "Trigger Postback",
payload: "DEVELOPER_DEFINED_PAYLOAD"
}, {
type: "phone_number",
title: "Call Phone Number",
payload: "+16505551234"
}]
}
}
}
};
callSendAPI(messageData);
}
/*
* Send a Structured Message (Generic Message type) using the Send API.
*
*/
function sendGenericMessage(recipientId) {
var messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "template",
payload: {
template_type: "generic",
elements: [{
title: "rift",
subtitle: "Next-generation virtual reality",
item_url: "https://www.oculus.com/en-us/rift/",
image_url: SERVER_URL + "/assets/rift.png",
buttons: [{
type: "web_url",
url: "https://www.oculus.com/en-us/rift/",
title: "Open Web URL"
}, {
type: "postback",
title: "Call Postback",
payload: "Payload for first bubble",
}],
}, {
title: "touch",
subtitle: "Your Hands, Now in VR",
item_url: "https://www.oculus.com/en-us/touch/",
image_url: SERVER_URL + "/assets/touch.png",
buttons: [{
type: "web_url",
url: "https://www.oculus.com/en-us/touch/",
title: "Open Web URL"
}, {
type: "postback",
title: "Call Postback",
payload: "Payload for second bubble",
}]
}]
}
}
}
};
callSendAPI(messageData);
}
/*
* Send a receipt message using the Send API.
*
*/
function sendReceiptMessage(recipientId) {
// Generate a random receipt ID as the API requires a unique ID
var receiptId = "order" + Math.floor(Math.random()*1000);
var messageData = {
recipient: {
id: recipientId
},
message:{
attachment: {
type: "template",
payload: {
template_type: "receipt",
recipient_name: "Peter Chang",
order_number: receiptId,
currency: "USD",
payment_method: "Visa 1234",
timestamp: "1428444852",
elements: [{
title: "Oculus Rift",
subtitle: "Includes: headset, sensor, remote",
quantity: 1,
price: 599.00,
currency: "USD",
image_url: SERVER_URL + "/assets/riftsq.png"
}, {
title: "Samsung Gear VR",
subtitle: "Frost White",
quantity: 1,
price: 99.99,
currency: "USD",
image_url: SERVER_URL + "/assets/gearvrsq.png"
}],
address: {
street_1: "1 Hacker Way",
street_2: "",
city: "Menlo Park",
postal_code: "94025",
state: "CA",
country: "US"
},
summary: {
subtotal: 698.99,
shipping_cost: 20.00,
total_tax: 57.67,
total_cost: 626.66
},
adjustments: [{
name: "New Customer Discount",
amount: -50
}, {
name: "$100 Off Coupon",
amount: -100
}]
}
}
}
};
callSendAPI(messageData);
}
/*
* Send a message with Quick Reply buttons.
*
*/
function sendQuickReply(recipientId) {
var messageData = {
recipient: {
id: recipientId
},
message: {
text: "What's your favorite movie genre?",
quick_replies: [
{
"content_type":"text",
"title":"Action",
"payload":"DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_ACTION"
},
{
"content_type":"text",
"title":"Comedy",
"payload":"DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_COMEDY"
},
{
"content_type":"text",
"title":"Drama",
"payload":"DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_DRAMA"
}
]
}
};
callSendAPI(messageData);
}
/*
* Send a read receipt to indicate the message has been read
*
*/
function sendReadReceipt(recipientId) {
console.log("Sending a read receipt to mark message as seen");
var messageData = {
recipient: {
id: recipientId
},
sender_action: "mark_seen"
};
callSendAPI(messageData);
}
/*
* Turn typing indicator on
*
*/
function sendTypingOn(recipientId) {
console.log("Turning typing indicator on");
var messageData = {
recipient: {
id: recipientId
},
sender_action: "typing_on"
};
callSendAPI(messageData);
}
/*
* Turn typing indicator off
*
*/
function sendTypingOff(recipientId) {
console.log("Turning typing indicator off");
var messageData = {
recipient: {
id: recipientId
},
sender_action: "typing_off"
};
callSendAPI(messageData);
}
/*
* Send a message with the account linking call-to-action
*
*/
function sendAccountLinking(recipientId) {
var messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "template",
payload: {
template_type: "button",
text: "Welcome. Link your account.",
buttons:[{
type: "account_link",
url: SERVER_URL + "/authorize"
}]
}
}
}
};
callSendAPI(messageData);
}
/*
* Call the Send API. The message data goes in the body. If successful, we'll
* get the message id in a response
*
*/
function callSendAPI(messageData) {
request({
uri: 'https://graph.facebook.com/v2.6/me/messages',
qs: { access_token: PAGE_ACCESS_TOKEN },
method: 'POST',
json: messageData
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
var recipientId = body.recipient_id;
var messageId = body.message_id;
if (messageId) {
console.log("Successfully sent message with id %s to recipient %s",
messageId, recipientId);
} else {
console.log("Successfully called Send API for recipient %s",
recipientId);
}
} else {
console.error("Failed calling Send API", response.statusCode, response.statusMessage, body.error);
}
});
}
// Start server
// Webhooks must be available via SSL with a certificate signed by a valid
// certificate authority.
app.listen(app.get('port'), function() {
console.log('Node app is running on port', app.get('port'));
});
module.exports = app;
接受参数并处理它的 CasperJS 脚本 (echo.js
):
var casper = require("casper").create();
if(casper.cli.has(0)) {
casper.echo("Received " + casper.cli.get(0));
}
casper.exit();
我现在使用以下命令来执行它:
casperjs echo.js input
它将回复:
Received input
我希望将“已收到输入”的内容回复给 Facebook 用户。我怎样才能实现这个目标?我如何连接这些组件?
谢谢。
最佳答案
您可以在某种异步任务( like a promise )或 in a background job 中运行 casper 工作。 .
您可以将发件人的 ID 和文本或您正在处理的任何内容(无法从源代码中看出)发送到后台作业或任务,并在作业中使用已处理的抓取数据与您的信使客户端进行响应。
在用处理后的数据做出响应之前,最好说“嘿用户,我正在抓取一些东西,只需要一秒钟”,以获得更好的用户体验。
A typing_on
message这里可能也不错,但是 YMMV。
关于javascript - 带有 NodeJS webhook + CasperJS 的 FB Messenger Bot,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42830499/
运行测试时获取。 FAIL 35 tests executed in 16.806s, 35 passed, 0 failed, 2 dubious, 0 skipped. “可疑”意味着什么?如何查
是否有人已经使用 casperjs 实现了著名的“页面对象模式”,从长远来看,它对于测试的可维护性非常有用? 当您必须将测试的机制和目的分开时,使用它非常非常酷。以这种方式编写测试会变得更加愉快。 有
所以,我试图在我的服务器上运行 casperJS 作为 cron 作业,这是 crontab: * * * * * /usr/local/bin/casperjs /var/www/javascrip
我知道如何禁用图像和插件,但似乎没有明显的选项来禁用 CasperJS 中的 css。 有谁知道这是如何工作的? 最佳答案 假设您想抑制所有外部样式表的加载,您可以通过中止加载 css 文件的请求来实
我在删除网站时从创建的 URL 下载文件时遇到问题。目前我发现了一个文件的月份和年份,然后替换了 url 中的值并尝试从该位置下载。我了解到您无法使用评估范围内的下载功能。 this.evaluate
在 CasperJS 中,如何在使用 casper.thenOpen() 时保持 session 例如: var casper = require('casper').create(); casper
我希望我的 casper 在 session 期间登录并保持登录状态。有可能吗?如果是这样,如何? 最佳答案 如果你想在 CasperJS 中存储 cookie,你可以使用 PhantomJS coo
我用 casperjs 编写了一些测试。他们与 phantomjs 一起运行得很好。但是,当我尝试通过以下命令使用 slimerjs 时: casperjs --verbose --engine=sl
我用 casperjs 编写了一些测试。他们与 phantomjs 一起运行得很好。但是,当我尝试通过以下命令使用 slimerjs 时: casperjs --verbose --engine=sl
我想单击“提交”按钮,等待下一页加载,然后在第二页上获取html。。我先做然后再运行,但然后一步仍在首页上运行。有任何想法吗? var casper = require('casper').creat
在我的页面自动化脚本中,当我单击标签链接时,将打开一个新窗口。链接的 url 是由复杂的 javascript 生成的。 办理任务 触发后 url 变为: https://oa.phicomm.co
CasperJS(带有 phantomJS)可以直接在浏览器中运行而不是通过命令行运行吗? 我想从浏览器运行交互式测试,我从用户那里获取输入并相应地进行。我想将 casperJS 作为在浏览器中执行的
我正在尝试使用 CasperJS 将图像上传到网络表单。 我的表格看起来像这样: ... Campaign Banner
错误: casper.test property is only available using the `casperjs test` command 在我的整个代码库中搜索了“casper.tes
假设我有一组网址。我不想使用 thenOpen 函数。因为它等待每个以前的 url 被加载并且它减少了加载时间。 casper.each(hrefs,function(self,href){
我正在尝试导航到从脚本本身创建的 url。 此示例代码不像(我曾)预期的那样工作。不知道为什么:( var casper = require('casper').create({ viewpo
我有一个链接列表,我必须模拟这些链接才能使用CasperJS进行点击。他们都共享同一个类(class)。 但是,使用this.click('.click-me')仅单击第一个链接。 单击所有链接的正确
casper.then(function(){ phone_number = '7wqeqwe6'; phone_password = 'Teqweqweqw34'; }); casper.t
我如何告诉 casper 不要加载图像、css、js 视频等。所以我只对 DOM 元素感兴趣。 最佳答案 看看 CasperJS API . var casper = require('casper'
在Phantom中生成PDF时,我可以这样设置纸张大小: page.paperSize = { height: '8.5in', width: '11in', orientation: '
我是一名优秀的程序员,十分优秀!