【发布时间】:2013-10-12 15:52:55
【问题描述】:
我之前在网上看到过很多关于这个的问题,但是,在大约 30 个论坛等等中,没有一个有我需要的解决方案,其中包括 stackoverflow。如果有人可以帮助我找到可靠的解决方案,将不胜感激,在此先感谢!
我将尽可能详细地解释我的网站和情况,以帮助任何想要帮助回答我的问题的人。这是我的情况:
我有一个网站,我使用 PHP 和 MySQL。我的网站是一个“私人”组织网站。为了允许人们访问该站点,我发送了我们组织的新成员并邀请代码。然后用户访问该网站,index.php 文件只包含一个用于登录的表单以及一个指向注册页面的链接。新会员点击“在此注册”链接开始注册。第一个注册页面询问用户的姓氏和邀请代码,这些信息会根据数据库进行检查,以确保该人在列表中并且尚未注册。如果他们通过检查,他们将被带到下一页,在其中输入所需信息(用户名和密码、电子邮件地址等)以及一些可选信息(电话、简历等)。如果用户创建了有效的用户名和密码并填写了所有必填字段,则他们的信息将存储在数据库中。密码都经过适当且安全的加盐和散列处理,因此没有问题,整个注册过程都可以正常进行。注册后,用户将返回 index.php,他们现在可以使用刚刚创建的用户名和密码登录。这也有效;当用户登录时,将根据数据库检查他们的用户名和密码,如果成功,则用户已登录。当用户登录时,数据库中的 ONLINE 值从 False 设置为 True。用户现在已登录并可以按预期使用该站点。在我的网站上,有一列列出了当前在线的用户(基于数据库中的 ONLINE 值)。当用户单击站点每个页面上的“注销”按钮时,logout.php 脚本将运行,结束会话并将 ONLINE 值设置回 False。这一切都很好而且花花公子,但是,当用户没有先注销就关闭浏览器时,问题就来了。这是我在互联网上不同地方看到许多不同“解决方案”的地方。我将解释为什么它们不起作用以及为什么我需要更好的解决方案。
我最常看到的答案涉及某种会话超时或破坏会话,这是无关紧要的,因为会话实际上已经在用户关闭浏览器时结束,但这对告诉没有影响其他用户,无论该人当前是否在线。会话结束时,数据库不会更新,这会导致问题,因为用户只能从单个实例登录。如果用户在其 ONLINE 值已设置为 TRUE 时尝试登录,则不允许他们登录。
我还看到了使用“Last Seen”值而不是在线值的建议,如果用户在过去 x 分钟内没有任何活动,请将用户注销。然而,这行不通,有两个原因。 1)该脚本仍然必须在某个地方运行才能使其工作,这意味着必须有另一个用户登录才能使其工作。这基本上意味着,如果使用此方法,如果用户关闭浏览器或断开连接,他们将无法重新登录,直到另一个用户登录。我的组织是一个小型的本地组织,因为它也就是说,可能有很多次没有用户在线。此外,即使其他用户登录,连接丢失的用户仍然无法重新登录,直到 x 分钟过去后,所以如果用户不小心关闭了浏览器并想立即重新登录,他们根本做不到。
我遇到的一个不太常见的解决方案涉及使用 onBeforeUnload JavaScript 函数,但这些解决方案肯定不会起作用,因为它们会在用户单击链接或“返回”和“前进”时触发纽扣。此外,如果用户在他们的浏览器中禁用了 JavaScript,这将根本不起作用。
我看到的最后一件事涉及 while 循环和 connection_aborted 函数,这是唯一一个似乎可以工作的东西,但我还没有看到关于它应该如何工作的非常清晰的描述,并且经过几个月的试验有了它,我仍然没有想出一个可靠的解决方案。
在许多论坛中,我看到人们说“这是不可能的”,但考虑到有些网站以某种方式做到这一点,情况并非如此。我已经在几个站点上对此进行了测试和试验。在拥有 Facebook 或任何论坛网站等用户的网站上,有一个“在线”用户列表,如果用户关闭浏览器,他们的名字将不再出现在列表中,所以有可能,即使只能通过一些晦涩难懂的方法来实现。因此,如果有人知道解决方案,如果您能分享您在这个问题上的一些智慧,我将不胜感激!
【问题讨论】:
-
您最好的办法是简单地合并一个不活动超时。如果在过去 10 或 15(或其他)分钟内没有任何活动,请注销此人。我不相信你认为这行不通的论点;正在运行的 Web 应用程序就是正在运行的 Web 应用程序。
-
也许有点牵强,或者实现起来的工作量太大,但您可以查看 socket.io,它提供了一种通过 HTTP 到客户端的非常可靠的传输方法,并且可以轻松检测到套接字断开连接。跨度>
-
您可以设计客户端浏览器代码,以在用户离开页面时发送结束用户会话的消息。但是,尽管您的直觉与此相反,您不能保证此类消息将始终由 Web 应用程序客户端代码发送。如果用户在您的窗口打开时从她的笔记本电脑中取出电池怎么办?您需要一个超时策略作为会话取消的备份。
-
@mobius 建议使用持久连接。猜猜 TCP 堆栈如何检测持久连接的丢失?超时。
-
@RobertHarvey 我知道这一切,但这不是问题所在。如果用户关闭浏览器或断开连接,超时将检查自上次登录以来的时间,这很好。问题是,如果用户的浏览器崩溃,他们可能希望重新启动浏览器并立即重新登录,但由于超时可能比他们重新启动浏览器并导航回网站需要 15 秒,导致用户必须等待超时到期才能重新登录。