В 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");
Если вы храните информацию о подкачке, сортировке, фильтрации и т. Д. На стороне сервера в качестве атрибута сеанса, вы должны хранить их отдельно, прикрепленные к отдельным идентификаторам окон.