В javascript, как я могу однозначно идентифицировать одно окно браузера из другого, которые находятся под тем же идентификатором сессии

Пользователи моего веб-приложения могут иметь несколько открытых окон браузера и указывать на одну и ту же страницу. Я бы хотел, чтобы состояние некоторых вещей на странице (загружаемых через ajax) сохранялось при обратной передаче. Я могу хранить файлы cookie или на моем сервере. В любом случае, я не могу думать о том, как я могу различить каждое окно.

Например, скажем, у пользователя Боба есть два окна браузера, открытые для страницы ListOfSomething. Каждый список имеет атрибут LoadedPageNumber, который мне нужно сохранить. В противном случае пользователи всегда оказываются на странице 1 при обновлении. Боб мог загрузить окно браузера 1 и указать его на странице 5, а затем загрузить окно 2 браузера и указать его на странице 14. Если я просто сохраню атрибут на основе идентификатора сеанса, Боб получит страницу 14 в окне 1, если обновит его.

Обратите внимание, что мои переменные состояния на самом деле намного сложнее, чем этот простой пример, и моя неспособность сохранить их может привести к большим проблемам (недостаткам в моем приложении).

Мне нужен какой-то идентификатор окна браузера или что-то в этом роде. Конечно, это должно быть кросс-браузерное решение (IE6+, Wekbit?+, FF2+)

Есть идеи?

Примечание об актуальности: имейте в виду, что это полезно также в случае, когда вы смешиваете старые страницы на основе форм с новыми элементами с поддержкой AJAX. Иногда вам нужно отправить обратно формы, и вы не хотите терять некоторые значения состояния на стороне клиента.

6 ответов

Решение

Вы можете установить собственное имя окна, точный синтаксис ускользает от меня прямо сейчас, но вы можете использовать текущее время и идентификатор сессии, чтобы создать уникальный идентификатор при загрузке окна, а затем использовать этот идентификатор

Это будет сделано так же, как вы устанавливаете имя в функции javascript window.open(), (но вы можете сделать это для себя, а не для нового окна)

Google показывает:

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, не поддерживаемое более старыми версиями IE.

Корпоративный по-прежнему сильно зависит от IE 7 ("и ниже" здесь, в Бразилии).

На основе self.window.name Решение для всего, не совместимого с HTML5, я предлагаю следующий фрагмент кода в качестве кросс-браузерного решения:

<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 здесь (для чего я предложил некоторую очистку кода).

Вы можете использовать хранилище сессий HTML5, просто сгенерировать уникальный идентификатор и установить его в хранилище сессий! что здорово в том, что каждое окно или вкладка имеет свое собственное хранилище сессии. например:

если мы запустим следующее в 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.

На самом деле, с новым API Web Locks вы можете получить фактический внутренний идентификатор окна (он же clientId). LockManager.query()может предоставить информацию о удерживаемых замках, включая идентификатор владельца. Может не работать в некотором контексте 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. Стыдно создавать такие неуклюжие конструкции только для того, чтобы получить информацию, которая должна быть легко доступна.

Это давным-давно, но ответ Роя Рико помог мне сегодня, поэтому я хочу поделиться своим опытом. Чтобы обработать обновление страницы и использование кнопки страницы, я делаю это так:

  • Ваш сервер проверяет, отправляет ли браузер 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, но я не хочу на это полагаться, потому что мне также нужен старый браузер для нормальной работы.

Как насчет того, чтобы ваш сервер генерировал случайный идентификатор и сохранял его на странице (некоторая переменная javascript), когда он обслуживается? Затем просто включите этот идентификатор в запрос ajax. Это не поможет при обновлении браузера, но до тех пор, пока пользователь оставляет эту страницу на месте (и просто позволяет ajax-компонентам делать свое дело), ​​она должна работать нормально.

window.name может быть перезаписано пользовательскими библиотеками javascript, датчиками времени и т. д.

Вместо window.name я предлагаю вам использовать метатег DOM head для хранения вашего идентификатора.

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

После загрузки страницы вы должны загрузить все через ajax в этом окне, затем вы можете прикрепить этот идентификатор к каждому запросу в качестве значения заголовка (или данных). Например, в JQuery с этим кодом:

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

Чтобы использовать это решение, вы должны иметь доступ к пользовательским значениям заголовка на стороне сервера. Например, в сервлете Java:

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

Если вы храните информацию о подкачке, сортировке, фильтрации и т. Д. На стороне сервера в качестве атрибута сеанса, вы должны хранить их отдельно, прикрепленные к отдельным идентификаторам окон.

Другие вопросы по тегам