【问题标题】:Detect Live Server Side changes (Long Polling, Short Polling or Web Sockets)检测实时服务器端更改(长轮询、短轮询或 Web 套接字)
【发布时间】:2013-05-07 19:16:08
【问题描述】:

论证与研究

我有一个需要用户登录才能查看的网站。当用户登录时,我想关注他们的用户会话。我的意思是我想知道他们的用户会话是否已经过期,因此重定向他们。

每个用户的会话持续 1 小时(或我设置的任何时间),如果他们访问不同的页面(如大多数登录系统),则会重置。

目前我有以下算法:

  1. 用户到达私密页面(调用isUserAuthorized()的javascript方法被执行)
  2. isUserAuthorized() javascript 方法向页面“ajax.example.net/authorized”发出 AJAX 请求
  3. 此页面返回一个指示用户当前状态的 JSON 对象,如下所示:

{ authorized: true, timeout: 3600000 }

  1. 然后 javascript 方法设置超时以在 timeout 毫秒内再次调用该方法,假设会话将在那时结束。
  2. 如果会话已结束,则重定向用户,否则在 timeout 毫秒内调用方法。

我不喜欢目前的方法有两个原因:

  1. 我遇到了客户端和服务器时钟之间的时间同步问题,这很奇怪,但肯定会导致问题...
  2. 它会在网页的后台留下一个超时,而且由于这个网站的 JavaScript 非常繁重,我宁愿没有这个额外的超时,以保持网站尽可能流畅。

我的问题

因此,我的问题是,有人能想出更好的方法来实现这一目标吗?我曾考虑过长轮询或 websockets,但我不是 100% 确定如何使用其中任何一个,而且我发现的 websockets 教程不是很好!这些实际上会是更好的解决方案吗?

我可以解决时间同步问题,但在此之前,我想确保没有更好的方法来实现这一点...

如果有帮助,这是我当前的代码:

// Set the Authorized Timeout
MN.authorizedTimeout = setTimeout(function(){MN.isUserAuthorized});

/**
 * Is User Authorized
 * Checks to see if the current user is authorized and
 * makes sure their session is still active
 */
MN.isUserAuthorized = isUserAuthorized;
function isUserAuthorized(){
    // TEMPORARY
    console.log('authorising');
    // Set the authorized var
    var authorized = false;
    // Clear the current timeout
    clearTimeout(MN.authorizedTimeout);
    // Send request to determine whether the user is authorized
    $.ajax({
        url: "//ajax.example.net/authorized",
        type: "GET",
        dataType: "JSON",
        cache: false,
        async: false,
        success: function(data){
            console.log(data);
            if(data.authorized){
                // If the user is authorized then check again in timeout milliseconds
                MN.authorizedTimeout = setTimeout(MN.isUserAuthorized,data.timeout_milliseconds);
                // Set authorized to true
                authorized = true;
            }else{
                // If the session has expired then proceed to informing the user
                MN.userSessionExpired();
                // Set authorized to false
                authorized = false;
            }
        }
    });
    // Return the session status boolean
    return authorized;
}

【问题讨论】:

    标签: php javascript jquery websocket long-polling


    【解决方案1】:

    更新答案:

    不过,我认为计算服务器端的在线状态是一种更好的做法。所以你可以确保没有与时间不一致。你只有你的服务器时间。

    为了获得在线状态,您可以采用长轮询方法。我给你做了个例子:

    (function checkLoginStatus(){
        $.ajax({ 
          type: 'POST',
          url: 'loginstatus.php',
          data: {userid : 25},
          success: function(data){
            if(data.logged_in !== true){
              //Log the user out
            }
          }, 
          dataType: "json", 
          complete: checkLoginStatus, 
          timeout: 15000 
        });
    })();
    

    这将确保仅在经过 15 秒且请求完成后才发出新请求。

    旧答案:

    如果您唯一关心的是监视已登录的用户,则无需轮询。我会保留整个服务器端。只需在您的用户表中添加一个“last_active”字段即可。

    每当用户交互(访问另一个站点)时,将时间戳更新为当前时间戳。

    要检测用户是否在线,获取当前时间戳并从中减去“last_active”时间戳。如果差异大于一小时,您就知道您的用户处于非活动状态。

    这就是我通常的处理方式。它也比这样做更有效率(关于资源) 使用 AJAX。

    【讨论】:

    • 感谢您的回答,但这并不是我真正想要的。我有一个审计表来告诉我用户上次活动的时间。我要做的是在用户会话过期时注销用户。知道他们的会话是否已过期的唯一方法是查看数据库并查看他们上次活动的时间......因此我必须有某种 AJAX 请求
    • 感谢您更新的答案。为了清楚起见,我正在处理我所有的用户会话服务器端。无需将任何内容传递到授权页面以指示谁已登录或任何其他内容。此页面仅提供登录用户状态的 JSON 对象。这是在服务器端生成的......与时间的不一致正是我问这个问题的原因,我想找到一种更好的方法来立即知道用户会话何时过期。考虑一下,用户打开一个页面 A,然后他在不同的选项卡中打开另一个页面 B。在页面 B,他点击了注销按钮 (续)
    • 点击注销按钮后,他显然是注销了,但页面A并没有反映这一点。如果他要尝试保存其中一个表格或页面上的任何内容,他会收到一个错误。实际上,我想要的是一个在用户会话结束后立即知道的系统,这可能归结为多种原因,无论是它已过期还是他已手动注销。我只想在会话结束后立即重定向用户。知道会话是否结束的唯一方法是查看服务器端,因此,短轮询、长轮询或 websockets...???
    【解决方案2】:

    从总体上看,您希望服务器上有一些东西可以在用户会话到期时提醒前端。

    长轮询可以做到这一点。基本上,您将拥有一个后端控制器,它接受连接并保留它们,直到它收到发送响应的信号或连接超时。所以你的前端会有一个循环,基本上发送一个请求并等待响应。如果响应返回为空,则表示超时,因此发送一个新请求。如果响应有内容,则不是超时,因此您可以采取行动。这实现了您的目标,并且许多此类系统都是以这种方式构建的。但是,反向使用 HTTP 是一种 hack,并且不会产生干净的代码。

    websocket 是客户端和服务器之间的双向接口。这是您的客户端 js 的样子。

      function connect(){
        websocket = new WebSocket("wss://yoursite.com:8080");
        //attach event handlers
        websocket.onmessage = onMessage;
      }
      function onMessage(evt){
        // do your thing
      }
    

    一旦您致电connect(),您就可以放心,当服务器需要到达客户端时,onMessage() 会为您服务。对我来说,从服务器向客户端发送消息正是我们拥有 websocket 的原因,因此它们是完成这项工作的正确工具。

    【讨论】:

    • +1 非常感谢您的回答。从我对 websockets 的发现来看,在 Windows 上安装它们并不是很简单。您是否知道任何好的教程,或者您可以指导我完成。我的大多数服务器都是 Linux,但是这个特定的项目在 MSSQL 数据库上运行,因此它必须是 Windows :-(
    • 你在使用任何网络框架吗?这里列出了一些 Windows 解决方案:en.wikipedia.org/wiki/Websocket
    • 不,害怕。我使用自己的框架...您推荐哪个?棘轮?过去我对网络套接字进行了很多研究,但网络上关于如何使用它们以及它们如何工作的信息非常少……终于找到知道他们在说什么的人真是太好了!感谢您到目前为止的时间! :-)
    • 我正在使用 Ratchet,但那是在 LAMP 服务器上,我大量使用 Symfony 作为 Web 框架。如果您没有也不需要 Web 框架,我会选择更轻量级的东西。你看过 node.js 吗?这似乎是一个非常受欢迎的选择。这是在 Windows 7 上设置回显服务器的教程:cjihrig.com/blog/websockets-in-node-js-0-8-6-for-windows-7
    猜你喜欢
    • 2011-06-06
    • 2013-05-25
    • 1970-01-01
    • 2013-11-13
    • 2012-06-10
    • 2018-12-30
    • 1970-01-01
    • 2013-11-11
    • 2013-08-13
    相关资源
    最近更新 更多