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

AppEngine channel API: duplicate messages client side

我正在尝试使用频道 API 将更新从服务器推送到客户端。流程是用户按下按钮触发服务器端操作,生成大量日志。我想向用户 "in real time" 显示日志。

当我第一次加载页面时,我收到了所有消息,没问题。如果我在没有刷新浏览器页面的情况下第二次触发该操作,那么所有消息都会出现两次。这是与页面 onLoad 事件相关联的通道的设置部分。通过生成的控制台日志,我收集到当页面未刷新时 onMessage() 方法被调用了不止一次。看起来我需要以某种方式 "kill" 更早的套接字,但在官方文档中找不到方法。有人可以指出正确的方向以消除虚假消息吗?

// 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);
}

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

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

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