【问题标题】:In javascript, how can I uniquely identify one browser window from another which are under the same cookiedbased sessionId在 javascript 中,如何从另一个基于 cookie 的会话 ID 下唯一地识别一个浏览器窗口
【发布时间】:2010-10-26 06:46:52
【问题描述】:

我的 Web 应用程序的用户可能打开了多个浏览器窗口并指向同一个页面。我希望在回发中保留页面中某些事物的状态(通过 ajax 加载)。我既可以存储在 cookie 中,也可以存储在我的服务器上。无论哪种方式,我都想不出如何区分每个窗口。

例如,假设用户 Bob 有两个浏览器窗口打开到 ListOfSomething 页面。每个列表都有一个我需要保留的 LoadedPageNumber 属性。否则,用户在刷新时总是在第 1 页结束。 Bob 可能已加载浏览器窗口 1 并将其指向第 5 页,然后加载浏览器窗口 2 并将其指向第 14 页。如果我仅根据会话 id 存储属性,则 Bob 将在窗口 1 中刷新第 14 页。

请注意,我的状态变量实际上比这个简单的示例要复杂得多,我无法持久化它们可能会导致大问题(我的应用程序中的弱点)。

我需要某种浏览器窗口 ID 或其他东西。当然需要是跨浏览器的方案(IE6+, Wekbit?+, FF2+)

有什么想法吗?

有关相关性的注意事项:请记住,这对于您将基于旧表单的页面与启用了 AJAX 的新项目混合在一起的情况也很有用。有时您需要回发表单并且不想丢失一些客户端状态值。

【问题讨论】:

    标签: ajax persistence state


    【解决方案1】:

    事实上,使用新的Web Locks API,您可以获得实际的内部窗口ID(又名clientId)。 LockManager.query() 可以提供有关持有锁的信息,包括所有者的 ID。由于安全限制,可能无法在某些 iframe 上下文中工作,但在顶部窗口中通常应该是好的。

    function getCurrentWindowId() {
        return new Promise((resolve) => {
            let lockName;
            tryGetLock(); // one attempt should almost always be enough
    
            function tryGetLock() {
                // generate some random lock name
                lockName = 'get-self-id-' + (Math.random() * 0xffffffff >>> 0);
                navigator.locks.request(lockName, { mode: 'exclusive', ifAvailable: true }, withLock);
            }
    
            function withLock(lock) {
                // unsing setTimeout(0) here to execute client's code after releasing the lock
                if (lock)
                    return navigator.locks.query()
                        .then(({ held }) => held.find(lock => lock.name === lockName).clientId)
                        .then(clientId => setTimeout(resolve, 0, clientId));
                else {
                    // unlucky - just try another lock
                    setTimeout(tryGetLock, 0);
                    return Promise.resolve();
                }
            }
        });
    }
    
    //usage
    
    getCurrentWindowId().then(clientId => {
       // do something with id
    });
    

    在 Firefox 96 和 Chrome 97 中工作。为了获得应该随时可用的信息而做出如此尴尬的结构感觉很可惜。

    【讨论】:

      【解决方案2】:

      您可以使用 HTML5 会话存储,只需生成一个唯一的 id 并将其设置在会话存储上! 每个窗口或选项卡都有自己的会话存储,这很酷。 例如:

      如果我们在 3 个窗口上运行以下命令:

      窗口 1: sessionStorage.setItem('key' , 'window1');

      窗口 2: sessionStorage.setItem('key' , 'window2');

      窗口 3: sessionStorage.setItem('key' , 'window3');

      sessionStorage.getItem('key' );

      窗口 1: sessionStorage.getItem('key' ); 返回窗口 1

      窗口 2: sessionStorage.getItem('key' ); 返回窗口 2

      窗口 3: sessionStorage.getItem('key'); 返回窗口 3

      我相信您正在尝试保存一个变量(分别在每个选项卡/窗口上)。

      sessionStorage 具有魅力。

      您可能面临的唯一问题是浏览器应该支持 HTML 5。

      【讨论】:

        【解决方案3】:

        window.name 可以被自定义 javascript 库、日期时间选择器等覆盖。

        我建议你使用 DOM head 元标记来代替 window.name 来存储你的 id

        <html><head><meta id="windowID" content="{YOUR ID}">
        

        页面加载后,您必须在该窗口中通过 ajax 加载所有内容,然后您可以将此 ID 作为标题(或数据)值附加到每个请求。例如在 JQuery 中使用以下代码:

        $(document)
            .ajaxSend(function(event, jqXHR, ajaxOptions) {
                jqXHR.setRequestHeader('windowID',
                    document.getElementById('windowID').content);
        })
        

        要使用此解决方案,您必须有权访问服务器端的自定义标头值。例如在 Java servlet 中:

        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String windowName = request.getHeader("windowID");
        

        如果您将分页、排序、过滤等信息存储在服务器端作为会话属性,您应该将它们单独存储,附加到单独的窗口 ID-s。

        【讨论】:

          【解决方案4】:

          很久以前,但是今天Roy Rico的回答对我有帮助,所以我想分享一下我的经验。为了处理页面刷新和页面后退按钮的使用,我这样做:

          • 您的服务器检查浏览器是否将 GUID 与他的请求一起发送(仅适用于 ajax 或表单提交)
          • 如果不存在(浏览器刷新、后退按钮),它只会发回一个带有小 JavaScript 脚本的页面。此脚本创建 GUID 并将其放入 window.name 存储中,如上所述。之后,脚本创建一个带有 GUID 作为隐藏字段的表单并将其提交给服务器。 action 属性使用与之前相同的 URL (window.location.href)

          --> 现在服务器识别 GUID 并可以根据需要传递内容。

          这是我的代码(出于安全原因,我在服务器上创建的 GUID,语法“${gUid} 来自 freemarker,只是从服务器插入 Guid):

          <script>
              $(window).load(
                  function () {
                      if (!window.name.match(/^GUID-/)) {
                          window.name = "GUID-" + "${gUid}";
                      }
                      $('<form action='+window.location.href+' method="POST"><input type="hidden" name="X-GUID" id="X-GUID" value='+window.name+'></form>').appendTo('body').submit();
                  }
              );  
          </script>
          

          希望对某人有所帮助

          顺便说一句,这种技术应该只用于“非 SEO 页面”,因为需要 JavaScript 来获取内容。但一般 SEO 页面不需要识别标签会话。

          当然现在你可以使用 HTML5 会话存储,但我不想依赖它,因为我还需要旧版浏览器才能正常工作。

          【讨论】:

            【解决方案5】:

            您可以设置自己的窗口名称,确切的语法现在让我无法理解,但您可以使用当前时间和会话 id 在窗口加载时创建一个唯一的 id,然后使用该 id

            这将与您在 javascript window.open() 函数中设置名称的方式相同,(但您可以对自己执行此操作,而不是新窗口)

            谷歌搜索显示:

            self.window.name = myclass.getUniqueWindowId(thisSession);

            更新

            关于您是否需要将其从刷新保存到刷新,我做了一些测试,它看起来可以将其从刷新保存到刷新。使用 Firefox 3,在初始加载时,窗口名称为空白,并反复按 CTRL+R,然后填充窗口名称。然后我注释掉设置名称代码并重新加载它仍然保留名称。

            <script type="text/javascript">
            
                alert( self.window.name );
            
                self.window.name = "blah";
            
            </script>
            

            更新

            我必须注意到下面关于 jQuery 的“jquery-session”插件的评论,它确实有效并且提供的方式比这里讨论的要多。

            虽然,但也应该明确表示它依赖于 HTML5 的 Web 存储,旧 IE 版本不支持

            企业仍然严重依赖 IE 7(巴西的“及以下”)。

            基于self.window.name,所有不符合 HTML5 的解决方案,我提供以下代码 sn-p 作为跨浏览器解决方案:

            <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
            <script language="javascript" type="text/jscript">
                //----------------------------------------------------------------------
                //-- guarantees that window.name is a GUID, and that it would
                //-- be preserved whilst this window's life cicle
                //----------------------------------------------------------------------
                //-- window.name will be set to "GUID-<SOME_RANDOM_GUID>"
                //----------------------------------------------------------------------
            
                $(window).load(
                    function () {
                        //----------------------
                        var GUID = function () {
                            //------------------
                            var S4 = function () {
                                return(
                                        Math.floor(
                                                Math.random() * 0x10000 /* 65536 */
                                            ).toString(16)
                                    );
                            };
                            //------------------
            
                            return (
                                    S4() + S4() + "-" +
                                    S4() + "-" +
                                    S4() + "-" +
                                    S4() + "-" +
                                    S4() + S4() + S4()
                                );
                        };
                        //----------------------
            
                        if (!window.name.match(/^GUID-/)) {
                            window.name = "GUID-" + GUID();
                        }
                    }
                ) //--------------------------------------------------------------------
            </script>
            

            我找到了 GUID 函数 here(我为此提出了一些代码清理建议)。

            【讨论】:

            【解决方案6】:

            让您的服务器随机生成一个 ID 并在提供该 ID 时将其存储在页面中(一些 javascript 变量)怎么样?然后只需在 ajax 请求中包含该 ID。它不会帮助刷新浏览器,但只要用户将该页面留在原处(并让 ajax 的东西做它的事情)它应该可以正常工作。

            【讨论】:

            • 我的问题是浏览器刷新。这就是问题的目标。
            • 查看我在下面添加的答案,了解如何解决刷新和后退按钮问题
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-23
            • 1970-01-01
            • 1970-01-01
            • 2015-04-02
            相关资源
            最近更新 更多