在使用JSP和Servlets在java中实现的Web应用程序中; 如果我在用户会话中存储信息,则从同一浏览器的所有选项卡共享此信息.如何在浏览器选项卡中区分会话?在这个例子中:
<%@page language="java"%> <% String user = request.getParameter("user"); user = (user == null ? (String)session.getAttribute("SESSIONS_USER") : user); session.setAttribute("SESSIONS_USER",user); %> <%=user %>
将此代码复制到jsp页面(testpage.jsp
)中,将此文件部署在服务器上的Web应用程序的现有上下文中(我使用Apache Tomcat),然后使用正确的URL(localhost/context1/testpage.jsp
)打开浏览器(FF,IE7或Opera ),键入您在输入中的姓名并提交表格.然后在同一浏览器中打开一个新选项卡,然后您可以在新选项卡上看到您的名称(从会话中获取).小心浏览器缓存,有时似乎不会发生,但它在缓存中,刷新第二个选项卡.
谢谢.
您可以使用HTML5 SessionStorage(window.sessionStorage).您将生成随机ID并保存在会话存储每个浏览器选项卡中.然后每个浏览器选项卡都有自己的ID.
使用sessionStorage存储的数据不会跨浏览器选项卡保留,即使两个选项卡都包含来自同一域源的网页也是如此.换句话说,sessionStorage中的数据不仅限于调用页面的域和目录,而且还包含页面所在的浏览器选项卡.与会话cookie相对照,会话cookie将数据从选项卡保留到选项卡.
您必须意识到服务器端会话是HTTP的人为附件.由于HTTP是无状态的,因此服务器需要以某种方式识别请求属于它知道并具有会话的特定用户.有两种方法可以做到这一点:
饼干.更干净,更流行的方法,但它意味着一个用户的所有浏览器标签和窗口共享会话 - IMO这实际上是可取的,我会非常恼火的一个网站让我登录每个新标签,因为我非常密集地使用标签
URL重写.网站上的任何URL都附加了会话ID.这是更多的工作(你必须在任何地方做一些你有站点内部链接的东西),但是可以在不同的选项卡中有单独的会话,虽然通过链接打开的选项卡仍然会共享会话.这也意味着用户在访问您的网站时始终必须登录.
无论如何你还想做什么?为什么要让标签有单独的会话?也许有一种方法可以在不使用会话的情况下实现目标?
编辑: 为了进行测试,可以找到其他解决方案(例如在不同的VM上运行多个浏览器实例).如果一个用户需要同时以不同的角色行事,那么应该在应用程序中处理"角色"概念,以便一个登录可以有多个角色.你必须决定是否使用URL重写,或者只是与当前情况一起生活是可以接受的,因为根本不可能使用基于cookie的会话单独处理浏览器选项卡.
你不应该.如果你想做这样的事情要么你需要强制用户通过动态编写URL来使用你的应用程序的单个实例,使用sessionID(不是sessionid它将无效)id并在每个URL中传递它.
我不知道你为什么需要它,但除非你需要制作一个完全无法使用的应用程序,否则不要这样做.
window.name Javascript属性是唯一可以在制表符活动中保留的东西,但可以保持独立(而不是URL guff).
我想出了一个新的解决方案,它有一点点开销,但似乎是原型的工作.一个假设是您正处于登录的荣誉系统环境中,尽管可以通过在切换选项卡时重新请求密码来进行调整.
使用localStorage(或等效的)和HTML5存储事件来检测新浏览器选项卡何时切换了哪个用户处于活动状态.当发生这种情况时,创建一个鬼重叠,其中包含一条消息,指出您无法使用当前窗口(或者暂时禁用该窗口,您可能不希望它显眼.)当窗口重新获得焦点时,发送一个AJAX请求记录用户回来了.
这种方法的一个警告:你不能有任何正常的AJAX调用(即,依赖于你的会话的调用)发生在没有焦点的窗口中(例如,如果你在延迟后发生了呼叫),除非在此之前手动进行AJAX重新登录调用.所以你需要做的就是首先检查你的AJAX函数以确保localStorage.currently_logged_in_user_id === window.yourAppNameSpace.user_id,如果没有,首先通过AJAX登录.
另一个是竞争条件:如果你可以快速切换窗口以使其混淆,你最终可能会得到一个relogin1-> relogin2-> ajax1-> ajax2序列,其中ajax1是在错误的会话下制作的.通过将登录AJAX请求推送到阵列,然后在存储上并在发出新的登录请求之前中止所有当前请求来解决此问题.
最后要注意的是窗口刷新.如果有人在您的AJAX登录请求处于活动状态但尚未完成时刷新窗口,则会以错误的人的名义刷新.在这种情况下,您可以使用非标准的beforeunload事件来警告用户潜在的混淆并要求他们单击取消,同时重新发出AJAX登录请求.然后他们可以解决它的唯一方法是在请求完成之前单击"确定"(或者不小心点击输入/空格键,因为OK - 不幸的是在这种情况下 - 是默认值.)还有其他方法来处理这种情况,比如检测F5和Ctrl + R/Alt + R按下,这在大多数情况下都有效,但可能会被用户键盘快捷键重新配置或替代操作系统使用所阻碍.然而,这实际上是一个边缘情况,最糟糕的情况永远不会那么糟糕:在荣誉系统配置中,你将以错误的人身份登录(但你可以明确表示这是案例通过个性化页面的颜色,样式,突出显示的名称等); 在密码配置中,最后一个人输入他们的密码以登出或共享他们的会话,或者如果这个人实际上是当前用户,则没有违规.
但最终你有一个单用户的每个标签应用程序(希望)只是按照它应该的方式运行,而不必设置配置文件,使用IE或重写URL.确保在登录到该特定选项卡的每个选项卡中明确显示,但...
我们遇到了这个问题,我们很容易解决了.我的意思很简单,因为没有编程.我们想要做的是让用户在同一浏览器窗口中登录多个帐户而不会使会话冲突.
因此,解决办法是随机的子域.
23423.abc.com 242234.abc.com 235643.abc.com
因此,我们要求我们的系统管理员很少的代码更改然后配置*.abc.com的SSL证书,而abc.com,每次用户尝试登录时,他被记录在一个随机数子域的一个标签.所以每个选项卡可以独立拥有自己的会话.同时,为了避免冲突,我们开发利用散列或用户ID的MD5随机数.
我会诚实的。。。所有上述可能或不可能是真实的,但是这一切似乎WAY太复杂,或者不涉及知道什么标签正在使用服务器端。
有时我们需要使用Occam的剃刀。
这是Occam的方法:(不,我不是Occam,他于1347年去世)
1)在加载时为您的页面分配一个浏览器唯一ID。。。当且仅当窗口还没有ID时(因此使用前缀和检测)
2)在您拥有的每个页面上(使用全局文件等),只需将代码放在适当的位置即可检测焦点事件和/或鼠标悬停事件。(为了简化代码编写,我将在这部分中使用jquery)
3)在焦点(和/或鼠标悬停)功能中,设置一个带有window.name的cookie
4)当您需要读/写选项卡特定数据时,从服务器端读取该cookie值。
客户端:
//Events $(window).ready(function() {generateWindowID()}); $(window).focus(function() {setAppId()}); $(window).mouseover(function() {setAppId()}); function generateWindowID() { //first see if the name is already set, if not, set it. if (se_appframe().name.indexOf("SEAppId") == -1){ "window.name = 'SEAppId' + (new Date()).getTime() } setAppId() } function setAppId() { //generate the cookie strCookie = 'seAppId=' + se_appframe().name + ';'; strCookie += ' path=/'; if (window.location.protocol.toLowerCase() == 'https:'){ strCookie += ' secure;'; } document.cookie = strCookie; }
服务器端(C#-例如)
//variable name string varname = ""; HttpCookie aCookie = Request.Cookies["seAppId"]; if(aCookie != null) { varname = Request.Cookies["seAppId"].Value + "_"; } varname += "_mySessionVariable"; //write session data Session[varname] = "ABC123"; //readsession data String myVariable = Session[varname];
做完了