前一段时间需要开发一个messenger的消息接口,但是facebook的官方文档似是而非,而且由于在国内比较小众,之前也没有另外的人写过中文的开发教程,只好自己进行了一番研究并完成了一个demo,希望给后来的人能带来一点方便。
一.创建Facebook应用和主页
https://developers.facebook.com/docs/messenger-platform/guides/quick-start
直接按照官方文档的第一步去完成即可
二.设置webhook
这里的webhook实际上就是你的第三方服务器,这里facebook的主页类似于微信的公众号。其中webhook的callback url就是回调函数的地址。类似于微信的服务器验证方式,这里的webhook也需要返回给facebook服务器指定的信息。
在 webhook 网址中,添加身份验证代码。此代码应对应上述验证口令,并以验证请求中发送的 challenge 为响应。点击“新建主页订阅”窗口中的“验证并保存”,以便通过 GET 请求调用 Webhook
然后给了一个官方案例,返回信息
app.get('/webhook', function(req, res) {
if (req.query['hub.mode'] === 'subscribe' &&
req.query['hub.verify_token'] === <VERIFY_TOKEN>) {
console.log("Validating webhook");
res.status(200).send(req.query['hub.challenge']);
} else {
console.error("Failed validation. Make sure the validation tokens match.");
res.sendStatus(403);
}
});
我不是很熟悉node.js,发现get[‘hub.verify_token’]并不能拿到并返回验证的信息,这里贴出我的php的验证方式
private function setupWebhook()
{
if(isset($_REQUEST['hub_challenge']) && isset($_REQUEST['hub_verify_token']) && $this->getValidationToken()==$_REQUEST['hub_verify_token'])
{
echo $_REQUEST['hub_challenge'];
exit;
}
}
hub_verify_token就是你自己设定的token,需要验证每次get的token,然后echo出hub_challenge
三.获取主页访问口令并订阅主页
建议把所有配置信息放在单独的文件里面,方便调用和修改。生成的口令不会在此界面保存。每次选择此主页都会生成一个新的口令。但之前生成的任何口令仍然有效。
四.接收消息
完成订阅后,系统需要在 webhook 中侦听 POST 调用。所有回调都将向此 webhook 发出。
Messenger Platform 的所有回调都使用相同的结构。
{
"object":"page",
"entry":[
{
"id":"PAGE_ID",
"time":1458692752478,
"messaging":[
{
"sender":{
"id":"USER_ID"
},
"recipient":{
"id":"PAGE_ID"
},
...
}
]
}
]
}
纯文字信息的详细结构
{
"object":"page",
"entry":[
{
"id":"PAGE_ID",
"time":1458692752478,
"messaging":[
{
"sender":{
"id":"USER_ID"
},
"recipient":{
"id":"PAGE_ID"
},
"timestamp":1458692752478,
"message":{
"mid":"mid.1457764197618:41d102a3e1ae206a38",
"seq":73,
"text":"hello, world!",
"quick_reply": {
"payload": "DEVELOPER_DEFINED_PAYLOAD"
}
}
}
]
}
]
}
附上webhook的参考文档的地址
https://developers.facebook.com/docs/messenger-platform/webhook-reference
- 1
关于具体处理消息的过程,我贴上我的代码
入口文件
require_once 'config.php';
require_once 'FacebookBot.php';
$bot = new FacebookBot(FACEBOOK_VALIDATION_TOKEN, FACEBOOK_PAGE_ACCESS_TOKEN);
$bot->run();
$messages = $bot->getReceivedMessages();
foreach ($messages as $message)
{
$recipientId = $message->senderId;
$text=$message->text;
if($text)
{
$bot->sendTextMessage($recipientId, $text);
}
elseif($message->attachments)
{
$bot->sendTextMessage($recipientId, "Attachment received");
}
}
定义类的文件
<?php
require_once 'config.php';
class FacebookBot
{
private $_validationToken;
private $_pageAccessToken;
private $_receivedMessages;
public function __construct($validationToken, $pageAccessToken)
{
$this->_validationToken = $validationToken;
$this->_pageAccessToken = $pageAccessToken;
$this->setupWebhook();
}
public function getReceivedMessages()
{
$this->run();
return $this->_receivedMessages;
}
public function getPageAccessToken()
{
return $this->_pageAccessToken;
}
public function getValidationToken()
{
return $this->_validationToken;
}
private function setupWebhook()
{
if(isset($_REQUEST['hub_challenge']) && isset($_REQUEST['hub_verify_token']) && $this->getValidationToken()==$_REQUEST['hub_verify_token'])
{
echo $_REQUEST['hub_challenge'];
exit;
}
}
public function sendTextMessage($recipientId, $text)
{
$url = "https://graph.facebook.com/v2.6/me/messages?access_token=%s";
$url = sprintf($url, FACEBOOK_PAGE_ACCESS_TOKEN);
$recipient = new stdClass();
$recipient->id = $recipientId;
$message = new stdClass();
$message->text = $text;
$parameters = ['recipient' => $recipient, 'message' => $message];
$response = self::executePost($url, $parameters, true);
if($response)
{
$responseObject = json_decode($response);
return is_object($responseObject) && isset($responseObject->recipient_id) && isset($responseObject->message_id);
}
return false;
}
public function run()
{
$request = self::getJsonRequest();
//var_dump($request);
if(!$request) return;
$entries = isset($request->entry) ? $request->entry : null;
if(!$entries) return;
$messages = [];
foreach ($entries as $entry)
{
$messagingList = isset($entry->messaging) ? $entry->messaging : null;
if(!$messagingList) continue;
foreach ($messagingList as $messaging)
{
$message = new stdClass();
$message->entryId = isset($entry->id) ? $entry->id : null;
$message->senderId = isset($messaging->sender->id) ? $messaging->sender->id : null;
$message->recipientId = isset($messaging->recipient->id) ? $messaging->recipient->id : null;
$message->timestamp = isset($messaging->timestamp) ? $messaging->timestamp : null;
$message->messageId = isset($messaging->message->mid) ? $messaging->message->mid : null;
$message->sequenceNumber = isset($messaging->message->seq) ? $messaging->message->seq : null;
$message->text = isset($messaging->message->text) ? $messaging->message->text : null;
$message->attachments = isset($messaging->message->attachments) ? $messaging->message->attachments : null;
$messages[] = $message;
}
}
$this->_receivedMessages = $messages;
}
private static function getJsonRequest()
{
$content = file_get_contents("php://input",true);
$return=json_decode($content, false, 512, JSON_BIGINT_AS_STRING);
return $return;
}
private static function executePost($url, $parameters, $json = false)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if($json)
{
$data = json_encode($parameters);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Content-Length: ' . strlen($data)));
}
else
{
curl_setopt($ch, CURLOPT_POST, count($parameters));
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parameters));
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
我这里做测试,返回的就是复述发送者的信息
六.测试
接入第三方平台和自己开发的差别还是很大的,起码报错消息你是看不见的,所以光从messenger那里发消息给主页是不方便调试的。
我这次用了shell下的curl来进行测试,用主页访问口令向 https://graph.facebook.com/v2.6/me/messages?access_token= 发出 POST 请求。负载必须以如下所述的 JSON 格式提供:
curl -X POST -H "Content-Type: application/json" -d '{
"recipient":{
"id":"USER_ID"
},
"message":{
"text":"hello, world!"
}
}' "https://graph.facebook.com/v2.6/me/messages?access_token=PAGE_ACCESS_TOKEN"
windows和linux略有区别。windows下建议用git bash等基于linux的环境而不要用cmd,例如上面的post请求,在cmd下其引号会失效,必须手动进行转义
七.关于一些坑
首先是facebook会偶尔向你的绑定的回调地址get消息,如果8个小时之内没有正确的返回的话,它就会自动解绑,我前一天晚上绑定的url第二天早上自动失效了,发现没有消息返回之后调了半天,才发现了这个问题。
其次是post回messenger的时候用了curl,需要开启php的curl,linux下的安装和windows不太一样,装的时候不要装错了php的版本,否则是不能生效的。
最后是messenger的应用没有提交审核之前是只能开发者发消息才有作用~
messenger的开发文档不算友好,全文算是译文吧,有的地方感觉比较生硬,比如它说的接受消息和发送消息是以用户做主体的,和一般人的理解还有一点出入。