AppEngine频道API:客户端重复消息

时间:2016-08-31 16:36:49

标签: google-app-engine channel-api

我正在尝试使用Channel API将更新从服务器推送到客户端。流程是用户按下一个按钮,该按钮触发生成大量日志的服务器端操作。我想实时向用户显示日志"。

当我第一次加载页面时,我收到所有消息,没问题。如果我第二次触发操作而不在浏览器中刷新页面,则所有消息都会出现两次。以下是与onLoad事件页面关联的通道的设置部分。使用生成的控制台日志,我收集了在未刷新页面时多次调用onMessage()方法。看起来我需要"杀死"早期的套接字在某种程度上,但在官方文档中找不到方法。有人能指出我正确的方向摆脱虚假信息吗?

// First fetch a token for the async communication channel and
// create the socket
$.post("/app/channels", {'op':'fetch', 'id' : nonce},
   function (data, status, xhr) {
       if (status == "success") {
       data = JSON.parse(data);
       token = data["token"];
       console.log("Cookie: " + get_mp_did() + "; token: " + token);
       var channel = new goog.appengine.Channel(token);
       var handler = {
           'onopen': onOpened,
           'onmessage': onMessage,
           'onerror': function() {
               $("#cmd_output").append('Channel error.<br/>');
           },
           'onclose': function() {
           $("#cmd_output").append('The end.<br/>');
           $.post("/app/channels", {'op':'clear'});
           }
       };
       var socket = channel.open(handler);
       socket.onopen = onOpened;
       socket.onmessage = onMessage;
       }
   });

onOpened = function() {
$("#cmd_output").empty();
};

onMessage = function(data) {
message = JSON.parse(data.data)['message'];
$("#cmd_output").append(message);
console.log('Got this sucker: ' + message);
}

1 个答案:

答案 0 :(得分:1)

如果我正确理解您的帖子和代码,用户点击调用$.post()功能的按钮。服务器代码负责在GAE中创建通道以响应/app/channels请求。我认为您的服务器实际上会为每个后续请求创建一个新的通道客户端ID /令牌。由于页面未重新加载,因此任何后续请求都会向此客户端添加新通道。并且所有这些频道仍将连接(因此,没有页面刷新)。

我假设您的服务器代码具有与用户关联的所有频道,并且您将消息发送给使用所有频道的用户?这种模式会导致这种行为。您可以通过在没有页面刷新的按钮上单击3或4次来验证我的假设。日志输出将乘以系数3或4。

我建议您将令牌存储在客户端和服务器上。然后对您的客户端JS进行修改。如果已创建通道,则存储令牌值并将其提供给/app/channels的任何后续请求。修改服务器,以便在请求提供令牌时不会创建新通道。如果令牌链接到现有有效通道,请重新使用该通道并在响应中返回相同的令牌。您可能需要为断开连接或过期的频道添加更多详细信息,也可能需要在一段时间后删除所有过期频道的cron-job。