HTTP session 和 CometD session 有不同的生命周期:例如,如果临时连接失败,CometD session 会失败,服务器会要求客户端重新握手,从而创建不同的 CometD session (代表同一个用户,但使用不同的 CometD clientId)。在相同的情况下,HttpSession 将保持不变。
考虑到这一点,您需要在应用程序级别维护用户名、通信方HttpSession 和通信方ServerSession 之间的映射。
我们称这个映射为HttpCometDMapper。
每次新用户登录时,您都要注册其名称(或用户的另一个唯一标识符)、HttpSession 和当前的ServerSession。
可能您需要一个两步过程,首先将用户名和HttpSession 关联起来,然后将相同的用户名与ServerSession 关联起来。
如果执行 CometD 重新握手,则使用新的 ServerSession 更新映射器。
您可以通过将HttpSessionListener 注册到HttpSession 来链接两个会话,这样当它被销毁时,您可以从映射器中检索当前的 CometD ServerSession 并在其上调用ServerSession.disconnect()。
反之亦然有点棘手,因为 CometD 没有像 HttpSession 那样的不活动超时概念。必须用你自己的逻辑在应用程序中实现。
其中一部分是在ServerSession 上注册RemoveListener,如下所示:
serverSession.addListener(new ServerSession.RemoveListener()
{
public void removed(ServerSession session, boolean timeout);
{
if (!timeout)
{
// Explicitly disconnected, invalidate the HttpSession
httpCometDMapper.invalidate(session);
}
}
});
此侦听器监视与客户端(和服务器的显式断开连接 - 谨防重入)。
稍微困难的是为非显式断开实现相同的机制。在这种情况下,timeout 参数将为真,但可能由于临时网络故障而发生(而不是客户端永远消失),并且同一用户可能已经与新的 ServerSession 重新握手.
我认为在这种情况下,应用程序超时可以解决问题:当您看到 ServerSession 由于超时而被删除时,您会注意到该用户并启动应用程序超时。如果同一个用户重新握手,取消应用超时;否则用户真的走了,应用程序超时到期,你也使HttpSession无效。
以上只是想法和建议;实际的实现很大程度上取决于应用程序的细节(这就是 CometD 不提供开箱即用的原因)。
关键点是映射器、HttpSessionListener 和RemoveListener,并了解这些组件的生命周期。
一旦你做到了这一点,你就可以编写为你的应用程序做正确事情的正确代码。
最后,请注意,CometD 有一种与传输无关的方式,可以通过BayeuxContext 实例与HttpSession 进行交互,您可以从BayeuxServer.getContext() 获得这种方式。
我建议你也看看它,看看它是否可以简化事情,特别是检索存储在HttpSession 中的令牌。