Facebook Messenger机器人未按顺序发送消息

16

我正在尝试构建一个简单的 Facebook Messenger 聊天机器人,并且我在发送连续消息方面遇到了问题。

enter image description here

在上面的示例中,它应该按顺序打印出 "Hello!"、"1"、"2"、"3"。我目前正在按照 这里 找到的 Facebook 文档来实现这个简单的文本消息功能。下面是我的 Express Node.JS 服务器代码:

定义 sendTextMessage() 函数:

var request = require("request");
function sendTextMessage(user, text) {
    messageData = {
        text: text
    };
    request({
        url: "https://graph.facebook.com/v2.6/me/messages",
        qs: {access_token: PAGE_ACCESS_TOKEN},
        method: "POST",
        json: {
            recipient: {id: user},
            message: messageData
        }
    }, function(error, response, body) {
        if (error) {
            console.log("Error sending message: ", error);
        } else if (response.body.error) {
            console.log("Error: ", response.body.error);
        } else {
            console.log("Message successfully send.")
        }
    });
}

使用它发送响应:

sendTextMessage(user, "Hello!");
sendTextMessage(user, "1");
sendTextMessage(user, "2");
sendTextMessage(user, "3");

我甚至尝试实现了一个简单的队列,它将消息排队,每次只在每个request成功回调之后发送一条消息。这使我怀疑我没有正确地与Messenger API交互。

有人遇到过这个问题吗?我该如何按顺序发送消息?谢谢!

编辑

因为我实现了一个简单的队列但仍然遇到这个问题,所以我在这里包含了我简单队列系统的代码。

var queue = [];
var queueProcessing = false;

function queueRequest(request) {
    queue.push(request);
    if (queueProcessing) {
        return;
    }
    queueProcessing = true;
    processQueue();
}

function processQueue() {
    if (queue.length == 0) {
        queueProcessing = false;
        return;
    }
    var currentRequest = queue.shift();
    request(currentRequest, function(error, response, body) {
        if (error || response.body.error) {
            console.log("Error sending messages!");
        }
        processQueue();
    });
}

queueRequest(/* Message 1 */);
queueRequest(/* Message 2 */);
queueRequest(/* Message 3 */);

更新

这个“漏洞”已经向Facebook报告,但看起来他们不打算修复它。请阅读Facebook帖子这里的工单线程,以了解他们所说的具体情况。(感谢Louise引起Facebook的注意)


@brain 你找到任何解决方法了吗? - Nagaraju
@Raju 我还没有找到明确的解决方案,但是如果你往下看,有人已经为此提交了一个错误报告,我相信正在处理中。我通过在消息队列上递归使用setTimeout来实现发送消息之间的任意1秒延迟,从而解决了这个问题。它可以工作,但似乎有点像hack。希望能帮到你! - Brian
你尝试在15秒内发送200响应了吗?我看到了这个提到相同问题的链接 - Stephen Tetreault
不,我没有,但那可能是一个潜在的方法。我现在已经不再从事这个项目了,但这个帖子似乎仍在持续受到关注,所以希望其他人偶然发现它时会觉得有所帮助。 - Brian
@RohanSood 我已经不再参与这个项目了,所以我没有再关注它。我最后知道的关于这个问题的事情是,有人向Facebook开发人员创建了一个错误报告,他们回应说这不是一个问题,也不会被修复:https://developers.facebook.com/bugs/565416400306038。Facebook开发者网站上的帖子应该能够为您提供更多帮助,以了解Facebook的官方回应是什么。希望这回答了你的问题! - Brian
显示剩余5条评论
11个回答

10

感谢您向Facebook提交该错误,希望他们能够修复! - Brian

4
当您向 /me/messages 发送 POST 请求后,将会收到一个回复,其中包含一个消息 ID(我的以 'mid.' 开头,可能代表消息 ID ?):
{ recipient_id: '1015411228555555',
  message_id: 'mid.1464375085492:b9606c00ca33c12345' }

在FB Messenger API完全接收后,您将收到一个调用您的Webhook(没有消息事件)以确认接收:

{ sender: { id: '1015411228555555' },
  recipient: { id: '566031806XXXXXX' },
  delivery:
   { mids: [ 'mid.1464375085492:b9606c00ca33c12345' ],
     watermark: 1464375085604,
     seq: 176 } }

我认为交付回执是确保消息传递的最佳方式,然后再发送下一条消息。

2
我的错误,根据最新的Facebook开发者笔记,交付收据并不是保证的,尽管这对于某些开发环境可能效果很好,但在生产中这种技术实际上并不是一个好方法。我们目前正在实施延迟,但必须有更好的方法来处理这个问题,即使在大规模情况下也是如此。 - younglion

2

你可以通过使用 Promise 来实现队列(Queuing)

function delay(time) {
  return new Promise(function(resolve, reject) {
    setTimeout(resolve, time);
  });
}

delay(2000).then(() => {
  console.log('hi');
  delay(2000).then(() => {
    console.log('hello');
    delay(2000).then(() => {
      console.log('welcome');
    })
  })
})


2

将发送请求实现为Promise,并仅在前一个消息解决后才发送连续的消息。

const send = (userId, messageData)  => {

      return new Promise((resolve, reject) => {
        request
        (
            {
                url     : BASE_URL + "me/messages",
                qs      : { access_token : PAGE_ACCESS_TOKEN },
                method  : "POST",
                json    : 
                        {
                            recipient: { id : userId },
                            message: messageData,
                        }
            }, (error, response, body) => 
            {
                if (error) { console.log("Error sending message: " + response.error); return reject(response.error); }
                else if (response.body.error) { console.log('Response body Error: ' + response.body.error); return reject(response.body.error); }

                console.log("Message sent successfully to " + userId); 
                return resolve(response);
            }
        );    
    });
};

1

不要添加静态超时时间,而是创建一个队列数据结构。当机器人想要发送消息时,将内容附加到队列末尾。在消息发布回调上,检查队列中是否仍有任何消息,并使用递归再次调用函数并相应地从队列中删除。


正如我在帖子底部提到的那样,我尝试实现了一个队列,在这个队列中,我会递归地发送消息,并在每次成功发送回调后继续发送。令人惊讶的是,这仍然没有起作用。 - Brian
@Brian是机器人,接收端和发送端在同一个网络上吗?也许检索是如此即时,以至于消息顺序在下载时被打乱了。 - Corn Doggo
我正在使用 messenger.com 作为与机器人交互的“客户端”。机器人本身作为 Node.js 应用程序在 Heroku 服务器上运行。 - Brian
@Brian 我需要对此进行研究,但我最好的猜测是,信使后端实际上也是异步的,不依赖于“发送”时间,而是后端将它们分发到接收端的时间,因此即使以队列格式发送它们也是不可靠的。也许你可以尝试队列系统,并在处理下一个队列之前添加任意延迟?至少这会给后端处理请求的一个小缓冲区。你还可以根据交付时间确定何时发送下一条消息,但这与此无关... - Corn Doggo
1
谢谢Chase,我很惊讶我没有找到任何类似的帖子。我也在自己研究这个问题,如果我找到了什么,我会更新的。我相信我不是唯一一个遇到这个问题的人! - Brian

0

消息没有按顺序发送,因为请求是异步发送到Facebook的,可以以任何顺序发送。

要解决这个问题,您必须在之前应该发送的消息收到响应后调用下一个sendTextMessage


0

它们应该按照发送的顺序接收。确保您实际上按顺序发送它们,而不是调用异步函数4次(并且发送顺序不能保证)。 (我看到您已经测试过了,但在我的所有测试中,如果发送顺序得到保证,我从未看到接收到来的顺序不正确。)


感谢您的输入。我刚编辑了我的帖子,并包含了我添加的简单排队功能的代码。您可以看一下并告诉我是否做得和您有所不同吗?再次感谢! - Brian

0

我曾经遇到过完全相同的问题,那个解决方案对我有用:

function sendMessage(recipient, messages, accessToken, i) {


    axios.post(baseURL + 'v2.11/me/messages/?access_token=' + accessToken,
        Object.assign({}, {
            messaging_type: "RESPONSE",
            recipient: {
                id: recipient
            }
        }, messages[i]['payload']) )
        .then(response => {

            if(i < messages.length) sendMessage( recipient, messages, accessToken, i+1 );

            },
            error => {})
        .catch(error => {});

}
sendMessage(recipient, flow['messages'], flow['page']['accessToken'], 0);

这是我的问题:使用Facebook Send-API进行顺序消息发送

0
我向应用程序添加了一个 messageId 计数器,在每次消息处理开始时将其重置为 0。然后,我使用该数字*100毫秒进行延迟。这样我就可以通过像 messageDelay += 15 这样的代码添加有意义的延迟。
receivedMessage(event) {
  messageDelay = 0;
  //...

sendMessage 扩展:

function sendTextMessage(recipientId, messageText) {
//...
  setTimeout(function() {
    callSendAPI(messageData);
  }, messageDelay++ * 100)    
}

0

基于@user3884594提出的递归解决方案,我使用以下方法使其工作(为了简化,我删除了错误处理):

send_messages (["message 01", "message 02", "message 03"]);

function send_messages (which, i = 0)
{
    request({
        url: 'https://graph.facebook.com/v2.10/me/messages',
        qs: { access_token: FACEBOOK_ACCESS_TOKEN },
        method: 'POST',
        json: { recipient: { id: senderId }, message: { text: which [i] }
    }, (error, response, body) => 
    {
        // You need to put your error handling logic here
        if (i++ < which.length - 1)
            send_messages (which, i);
    });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接