sesión del navegador Almacenamiento. compartir entre pestañas?

151

Tengo algunos valores en mi sitio que quiero borrar cuando el navegador está cerrado. Elegí sessionStoragealmacenar esos valores. Cuando se cierra la pestaña, se borran y se mantienen si el usuario presiona f5; Pero si el usuario abre algún enlace en una pestaña diferente, estos valores no estarán disponibles.

¿Cómo puedo compartir sessionStoragevalores entre todas las pestañas del navegador con mi aplicación?

El caso de uso: coloque un valor en algún almacenamiento, mantenga ese valor accesible en todas las pestañas del navegador y desactívelo si todas las pestañas están cerradas.

if (!sessionStorage.getItem(key)) {
    sessionStorage.setItem(key, defaultValue)
}
Vladimir Gordienko
fuente
9
Es extraño para mí que esto se haya cerrado como un duplicado. Nominación para reapertura. El otro tema trata sobre "cómo comunicarse entre múltiples pestañas", que suena diferente, y también es diferente, cuando empiezo a leer ese otro tema.
KajMagnus
¿Es posible usar cookies? que se comportan así por defecto? (pero de hecho, para obtener y establecer una acción exigirán una mayor implementación) developer.mozilla.org/en-US/docs/Web/API/Document/cookie
lingar

Respuestas:

133

Puede usar localStorage y su EventListener de "almacenamiento" para transferir datos de sessionStorage de una pestaña a otra.

Este código debería existir en TODAS las pestañas. Debería ejecutarse antes que sus otros scripts.

// 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');
};

Probé esto en cromo, ff, safari, es decir, 11, es decir, 10, es decir, 9

Este método "debería funcionar en IE8" pero no pude probarlo ya que mi IE fallaba cada vez que abría una pestaña ... cualquier pestaña ... en cualquier sitio web. (bueno, IE) PD: obviamente necesitarás incluir una cuña JSON si también quieres soporte para IE8. :)

El crédito va a este artículo completo: http://blog.guya.net/2015/06/12/sharing-sessionstorage-between-tabs-for-secure-multi-tab-authentication/

nawlbergs
fuente
2
¿Qué tan confiable es esta solución? Dado que está basado en eventos, ¿hay alguna posibilidad de perderse un evento?
vivek241
2
Basado en las respuestas aquí, creé una biblioteca sobre localStorage y sessionStorage para simplificar esto. Entonces ahora solo llama a storageManager.saveSyncedSessionData ('data', 'key'); o storageManager.savePermanentData ('data', 'key') ;, etc., según lo que necesite. El código completo está aquí: ebenmonney.com/blog/…
adentum
@ vivek241 La solución funcionó muy bien para mí cuando el tamaño del archivo JS era más pequeño y "la secuencia de comandos de la solución" dada anteriormente se carga como la primera secuencia de comandos en la página. Cuando mi archivo JS creció demasiado, digamos 1000 o más líneas, de repente dejó de funcionar y también eliminó mis cookies y datos específicos de almacenamiento local. No estoy seguro de que sea una solución confiable o de navegador cruzado en la que se pueda confiar. Entonces, reescribió toda la lógica para resolver el problema solo con las cookies.
webblover
44
¿No se activaría el evento en todas las pestañas abiertas anteriormente?
Dtipson
3
Se ve como BroadcastChannel ahora es una buena herramienta para hacer esto. developers.google.com/web/updates/2016/09/broadcastchannel
alexbea
71

Usar sessionStoragepara esto no es posible.

De los documentos de MDN

Al abrir una página en una nueva pestaña o ventana, se iniciará una nueva sesión.

Eso significa que no puede compartir entre pestañas, para esto debe usar localStorage

Henrik Andersson
fuente
8
Ok, lo tengo, pero ¿cómo puedo borrar localStorage cuando todas las pestañas del navegador están cerradas?
Vladimir Gordienko
Puede cambiar la cookie de documentos para path='/'obligarla a eliminarse cuando se cierre la ventana del navegador. Pero para pestañas, no tengo idea en este momento.
Henrik Andersson
ok, profundizaré más y te haré saber si encuentro una solución, deja pensar por ahora qué es imposible))
Vladimir Gordienko
55
@ Anmol sí, pero ya no puedo proporcionar ningún código, fue hace mucho tiempo. Esta es una solución fea, pero me funciona perfectamente. La clave es mantener el contador de pestañas abiertas en el almacenamiento local y aumentarlo en la carga de la página, pero disminuir en la descarga de la página. Entonces, cuando la página se descarga y tabsOpen == 1 su última pestaña y podemos borrar todo. Había algunas cosas menores que tenía que manejar, pero no recuerdo exactamente qué. ¡Espero que te ayude!
Vladimir Gordienko
1
@VladimirGordienko, ¿qué pasa si el evento de descarga que elimina los localStoragedatos ocurre porque alguien navega a un dominio diferente, en la misma pestaña? Me parece que esto eliminará incorrectamente los localStoragedatos: la pestaña no se cerró, y si la persona navega hacia atrás, querría los datos nuevamente, correcto. De todos modos, es un enfoque interesante, no pensé en eso: -)
KajMagnus
9
  1. Puede usar localStoragey recordar la fecha en que se creó por primera vez session cookie. Cuando localStorage"sesión" es anterior al valor de la cookie, puede borrar ellocalStorage

    Contras de esto es que alguien aún puede leer los datos después de cerrar el navegador, por lo que no es una buena solución si sus datos son privados y confidenciales.

  2. Puede almacenar sus datos localStoragedurante un par de segundos y agregar un detector de eventos para un storageevento. De esta manera, sabrá cuándo alguna de las pestañas escribió algo en el localStoragey puede copiar su contenido en el sessionStorage, luego simplemente borre ellocalStorage

Adassko
fuente
0

Mi solución para no tener sessionStorage transferible a través de pestañas fue crear un perfil local y aprovechar esta variable. Si esta variable está configurada pero mis variables sessionStorage no están adelante, reinícielas. Cuando el usuario cierra sesión, la ventana se cierra y destruye esta variable localStorage

yardpenalty.com
fuente
-14

Aquí hay una solución para evitar el corte de sesión entre pestañas del navegador para una aplicación Java. Esto funcionará para IE (JSP / Servlet)

  1. En su primera página JSP, el evento onload llama a un servlet (llamada ajex) para configurar un "window.title" y un rastreador de eventos en la sesión (solo una variable entera que se establecerá como 0 por primera vez)
  2. Asegúrese de que ninguna de las otras páginas establezca una ventana.
  3. Todas las páginas (incluida la primera página) agregan un script java para verificar el título de la ventana una vez que se completa la carga de la página. si no se encuentra el título, cierre la página / pestaña actual (asegúrese de deshacer la función "window.unload" cuando esto ocurra)
  4. Configure la página page.onunload java script event (para todas las páginas) para capturar el evento de actualización de la página, si una página se ha actualizado, llame al servlet para restablecer el rastreador de eventos.

1) primera página 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 común para todas las páginas

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 - mapeo de servlet

<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) código de servlet

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
fuente
3
Esta pregunta es sobre JavaScript, no tiene nada que ver con JavaScript.
victorpacheco3107
Esta pregunta es más sobre sessionStorage y localStorage
RR1112