Сеанс браузера. поделиться между вкладками?

151

У меня есть некоторые значения на моем сайте, которые я хочу очистить при закрытии браузера. Я решил sessionStorageхранить эти значения. Когда вкладка закрыта, они действительно очищаются и сохраняются, если пользователь нажимает клавишу f5; Но если пользователь открывает какую-либо ссылку на другой вкладке, эти значения будут недоступны.

Как я могу поделиться sessionStorageзначениями между всеми вкладками браузера с моим приложением?

Вариант использования: поместите значение в какое-то хранилище, оставьте его доступным на всех вкладках браузера и снимите его, если все вкладки закрыты.

if (!sessionStorage.getItem(key)) {
    sessionStorage.setItem(key, defaultValue)
}
Владимир Гордиенко
источник
9
Мне странно, что это закрыто как дубликат. Номинация на повторное открытие. Другая тема о том, «как общаться между несколькими вкладками», что звучит по-разному, а также по-другому, когда я начинаю читать эту другую тему.
КаджМагнус
Можно ли использовать куки? которые ведут себя так по умолчанию? (но на самом деле - для получения и установки действия они потребуют дальнейшей реализации) developer.mozilla.org/en-US/docs/Web/API/Document/cookie
lingar

Ответы:

133

Вы можете использовать localStorage и его «хранилище» eventListener для передачи данных sessionStorage с одной вкладки на другую.

Этот код должен существовать на ВСЕХ вкладках. Он должен выполняться перед вашими другими сценариями.

// transfers sessionStorage from one tab to another
var sessionStorage_transfer = function(event) {
  if(!event) { event = window.event; } // ie suq
  if(!event.newValue) return;          // do nothing if no value to work with
  if (event.key == 'getSessionStorage') {
    // another tab asked for the sessionStorage -> send it
    localStorage.setItem('sessionStorage', JSON.stringify(sessionStorage));
    // the other tab should now have it, so we're done with it.
    localStorage.removeItem('sessionStorage'); // <- could do short timeout as well.
  } else if (event.key == 'sessionStorage' && !sessionStorage.length) {
    // another tab sent data <- get it
    var data = JSON.parse(event.newValue);
    for (var key in data) {
      sessionStorage.setItem(key, data[key]);
    }
  }
};

// listen for changes to localStorage
if(window.addEventListener) {
  window.addEventListener("storage", sessionStorage_transfer, false);
} else {
  window.attachEvent("onstorage", sessionStorage_transfer);
};


// Ask other tabs for session storage (this is ONLY to trigger event)
if (!sessionStorage.length) {
  localStorage.setItem('getSessionStorage', 'foobar');
  localStorage.removeItem('getSessionStorage', 'foobar');
};

Я проверял это в chrome, ff, safari, т.е. 11, т.е. 10, ie9

Этот метод "должен работать в IE8", но я не мог проверить его, так как мой IE зависал каждый раз, когда я открывал вкладку ... любую вкладку ... на любом веб-сайте. (хорошо, IE) PS: вам, очевидно, нужно будет включить JSON-прокладку, если вам нужна поддержка IE8. :)

Авторы этой статьи: http://blog.guya.net/2015/06/12/sharing-sessionstorage-between-tabs-for-secure-multi-tab-authentication/

nawlbergs
источник
2
Насколько надежно это решение? Поскольку он основан на событиях, есть ли шанс пропустить событие?
vivek241
2
Основываясь на ответах здесь, я создал библиотеку поверх localStorage и sessionStorage, чтобы упростить это. Так что теперь вы просто вызываете storageManager.saveSyncedSessionData ('data', 'key'); или storageManager.savePermanentData ('data', 'key'); и т. д. в зависимости от того, что вам нужно. Полный код здесь: ebenmonney.com/blog/...
adentum
@ vivek241 Решение отлично сработало для меня, когда размер файла JS был меньше, а приведенный выше «сценарий решения» загружается в качестве первого сценария на странице. Когда мой JS-файл стал слишком большим, скажем, на 1000 или более строк, он внезапно перестал работать и также удалил мои файлы cookie и определенные данные localStorage. Я не уверен, что это надежное или кросс-браузерное решение, на которое можно положиться. Итак, переписал всю логику, чтобы решить проблему только с cookie.
веб-журнал
4
Разве событие не будет запущено во всех ранее открытых вкладках?
Dtipson
3
Похоже, BroadcastChannelсейчас это хороший инструмент для этого. developers.google.com/web/updates/2016/09/broadcastchannel
alexbea
71

Использование sessionStorageдля этого невозможно.

Из документов MDN

Открытие страницы в новой вкладке или окне приведет к началу нового сеанса.

Это означает, что вы не можете поделиться между вкладками, для этого вы должны использовать localStorage

Хенрик Андерссон
источник
8
Хорошо, я понял, но как я могу очистить localStorage, когда все вкладки браузера закрыты?
Владимир Гордиенко
Вы можете изменить cookie-файл документов, чтобы path='/'он очищался при закрытии окна браузера. Но о вкладках я понятия не имею прямо сейчас.
Хенрик Андерссон
хорошо, я буду копать глубже и дам вам знать, если я нашел решение, давайте пока подумаем, что это невозможно))
Владимир Гордиенко
5
@Anmol да, но я не могу предоставить какой-либо код уже, это было далеко назад. это уродливое решение, но оно прекрасно работает для меня. Ключом здесь является сохранение счетчика tabsOpened в локальном хранилище и увеличение его при загрузке страницы, но уменьшение при выгрузке страницы. Поэтому, когда страница выгружается и tabsOpen == 1 ее последняя вкладка, мы можем очистить все. Были некоторые незначительные вещи, с которыми я должен был справиться, но не могу вспомнить, что именно. Надеюсь, это поможет Вам!
Владимир Гордиенко
1
@VladimirGordienko, что если событие unload, которое удаляет localStorageданные, происходит из-за того, что кто-то переходит в другой домен, на той же вкладке. Мне кажется, это приведет к неправильному удалению localStorageданных - вкладка не будет закрыта, и если человек вернется назад, он / она захочет получить данные снова, верно. Во всяком случае, это интересный подход, не думал об этом: -)
KajMagnus
9
  1. Вы можете просто использовать localStorageи запомнить дату, в которую он был впервые создан session cookie. Когда localStorage«сессия» старше значения cookie, вы можете очиститьlocalStorage

    Недостатком этого является то, что кто-то еще может прочитать данные после закрытия браузера, так что это не очень хорошее решение, если ваши данные являются конфиденциальными и конфиденциальными.

  2. Вы можете сохранить свои данные в localStorageтечение нескольких секунд и добавить прослушиватель событий для storageсобытия. Таким образом, вы узнаете, когда какая-либо из вкладок что-то написала, localStorageи сможете скопировать ее содержимое в sessionStorage, а затем просто очиститеlocalStorage

Adassko
источник
9

На самом деле, глядя на другие области, если вы открываете с помощью _blank, он сохраняет sessionStorage, пока вы открываете вкладку, когда родительский элемент открыт:

В этой ссылке есть хороший jsfiddle для тестирования. sessionStorage в новом окне не пуст, при переходе по ссылке с target = "_ blank"

Дэн Паркер
источник
0

Моим решением, чтобы сессионное хранилище не передавалось через вкладки, было создание localProfile и удаление этой переменной. Если эта переменная установлена, но мои переменные sessionStorage не идут дальше и повторно инициализируют их. Когда пользователь выходит из окна закрывается, уничтожьте эту переменную localStorage

yardpenalty.com
источник
-14

Вот решение для предотвращения среза сеанса между вкладками браузера для Java-приложения. Это будет работать для IE (JSP / Servlet)

  1. На вашей первой странице JSP событие onload вызывает сервлет (вызов ajex), чтобы установить в окне «window.title» и средство отслеживания событий (просто целочисленная переменная, которая будет установлена ​​в 0 в первый раз)
  2. Убедитесь, что ни одна из других страниц не установила window.title
  3. На всех страницах (включая первую страницу) добавляется сценарий Java для проверки заголовка окна после завершения загрузки страницы. если заголовок не найден, закройте текущую страницу / вкладку (при этом обязательно отмените функцию «window.unload»)
  4. Задайте событие java-скрипта окна window.onunload (для всех страниц) для захвата события обновления страницы, если страница была обновлена, вызовите сервлет для сброса трекера событий.

1) первая страница JS

BODY onload="javascript:initPageLoad()"

function initPageLoad() {
    var xmlhttp;

    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else {
        // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }

    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {                           var serverResponse = xmlhttp.responseText;
            top.document.title=serverResponse;
        }
    };
                xmlhttp.open("GET", 'data.do', true);
    xmlhttp.send();

}

2) общий JS для всех страниц

window.onunload = function() {
    var xmlhttp;
    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else {
        // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {             
            var serverResponse = xmlhttp.responseText;              
        }
    };

    xmlhttp.open("GET", 'data.do?reset=true', true);
    xmlhttp.send();
}

var readyStateCheckInterval = setInterval(function() {
if (document.readyState === "complete") {
    init();
    clearInterval(readyStateCheckInterval);
}}, 10);
function init(){ 
  if(document.title==""){   
  window.onunload=function() {};
  window.open('', '_self', ''); window.close();
  }
 }

3) web.xml - отображение сервлета

<servlet-mapping>
<servlet-name>myAction</servlet-name>
<url-pattern>/data.do</url-pattern>     
</servlet-mapping>  
<servlet>
<servlet-name>myAction</servlet-name>
<servlet-class>xx.xxx.MyAction</servlet-class>
</servlet>

4) код сервлета

public class MyAction extends HttpServlet {
 public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException {
    Integer sessionCount = (Integer) request.getSession().getAttribute(
            "sessionCount");
    PrintWriter out = response.getWriter();
    Boolean reset = Boolean.valueOf(request.getParameter("reset"));
    if (reset)
        sessionCount = new Integer(0);
    else {
        if (sessionCount == null || sessionCount == 0) {
            out.println("hello Title");
            sessionCount = new Integer(0);
        }
                          sessionCount++;
    }
    request.getSession().setAttribute("sessionCount", sessionCount);
    // Set standard HTTP/1.1 no-cache headers.
    response.setHeader("Cache-Control", "private, no-store, no-cache, must-                      revalidate");
    // Set standard HTTP/1.0 no-cache header.
    response.setHeader("Pragma", "no-cache");
} 
  }
DTB
источник
3
Этот вопрос о javascript, он не имеет ничего общего с javascript.
victorpacheco3107
Это вопрос больше о sessionStorage и localStorage
RR1112