use localStorage em subdomínios

95

Estou substituindo cookies por localStorage em navegadores que podem suportá-lo (qualquer um, exceto o IE). O problema é site.com e www . site.com armazena seus próprios objetos localStorage separados. Eu acredito que www é considerado um subdomínio (uma decisão estúpida se você me perguntar). Se um usuário estava originalmente em site.com e decide digitar www . site.com em sua próxima visita, todos os seus dados pessoais estarão inacessíveis. Como faço para que todos os meus "subdomínios" compartilhem o mesmo localStorage do domínio principal?

JoJo
fonte
4
O Firefox e o IE8 oferecem suporte ao armazenamento de dados persistentes em um domínio especificado pelo usuário. Por exemplo, no FF, você pode fazer globalStorage ['site.com'] e isso será acessível para www.site.com e site.com. Ainda não descobri como fazer isso na implementação do Chrome.
JoJo
9
Considere usar um ou o último - redirecione todos os usuários que visitam com o www. subdomínio para o domínio sem subdomínio ou vice-versa.
Elad Nava
Eu criei o artigo há muito tempo: Cross-Domain LocalStorage
jcubic

Respostas:

94

É assim que eu o uso em vários domínios ...

  • Use um iframe de seu domínio principal - diga parent.com
  • Em seguida, em cada domínio child.com, basta enviar uma postagem para o iframe parent.com
  • Tudo o que você precisa fazer é configurar um protocolo de como interpretar suas mensagens postMessage para falar com o iframe parent.com.

Espero que ajude :)

Mayank Jain
fonte
2
Esta é a resposta real, não aquela que foi marcada. Eu mesmo fiz isso, mas também criei um wrapper de retorno de chamada conveniente com postMessage.
Jason Sebring
4
Aqui está um bom artigo com alguns exemplos de código que explicam esse método: jcubic.wordpress.com/2014/06/20/cross-domain-localstorage
Todd Price
4
Observe que isso só é possível quando os cookies de terceiros não estão desativados: stackoverflow.com/a/44097269/4311428
máximo de
6
A Apple atualizou os padrões do Safari 7+ no desktop e no celular para bloquear dados de terceiros. A opção agora é chamada de "Bloquear cookies e outros dados do site", que se refere a coisas como armazenamento local, que agora estão completamente isolados por domínio. Este método não funcionará no Safari
Aranganathan
2
@Max @Aranganathan ainda funciona para o caso de pergunta original - site.com/ www.site.comcontanto que os subdomínios estejam no mesmo domínio pai
Kostiantyn
40

Se você estiver usando a solução iframe e postMessage apenas para este problema específico, acho que pode ser menos trabalhoso (tanto em termos de código quanto de computação) apenas armazenar os dados em um cookie sem subdomínio e, se ainda não estiver em localStorage no carregamento, pegue-o do cookie .

Prós:

  • Não precisa de iframe e postMessage extras configurados.

Contras:

  • Tornará os dados disponíveis em todos os subdomínios (não apenas em www), portanto, se você não confiar em todos os subdomínios, pode não funcionar para você.
  • Enviará os dados ao servidor em cada solicitação. Não é ótimo, mas dependendo do seu cenário, talvez ainda menos trabalho do que a solução iframe / postMessage.
  • Se você está fazendo isso, por que não usar os cookies diretamente? Depende do seu contexto.
  • Tamanho máximo do cookie de 4 K, total em todos os cookies do domínio (obrigado a Blake por apontar isso nos comentários)

Eu concordo com outros comentadores, porém, parece que deve ser uma opção especificável para localStorage, portanto, não são necessárias soluções alternativas.

Matt
fonte
29
Contra: tamanho máximo de cookie de 4k
Blake Miller,
17
Além disso, como aprendi da maneira mais difícil, o limite de 4k é para a soma dos tamanhos de todos os cookies para um único domínio, não para cada cookie.
Blake Miller
outros contras: - os cookies serão mais provavelmente bloqueados por adblockers - os cookies destinam-se a ser usados ​​para compartilhar pequenos dados entre o servidor e o cliente, se o servidor não estiver usando os dados que você armazena no cookie, isso é conseqüentemente um uso indevido
Enno
32

Eu sugiro fazer o site.com redirecionar para www.site.com para consistência e para evitar problemas como este.

Além disso, considere o uso de uma solução para vários navegadores como PersistJS, que pode usar o armazenamento nativo de cada navegador.

Eran Galperin
fonte
Não tenho acesso de administrador aos servidores para fazer esse redirecionamento. Essa biblioteca me permite compartilhar dados persistentes entre www e não-www? Depois de fazer algumas leituras, parece que quase todos os mecanismos de armazenamento dos navegadores não permitem isso. Não importa se são cookies ou localStorage, vamos ter este problema ...
JoJo
Sim, o armazenamento normalmente depende do domínio, incluindo o subdomínio. É por isso que sugeri um redirecionamento. Você não precisa necessariamente de acesso de administrador, apenas use uma regra .htaccess na raiz do documento
Eran Galperin
1
@JoJo Existem várias maneiras de redirecionar, por exemplo, enviando o cabeçalho Location, ou através da <meta>tag HTML, ou mesmo JS via window.location.
Sony Santos
1
Isso é apenas evitar a resposta. Veja a resposta de Mayank como correta.
Jason Sebring
1
+1 @avoiding, além disso, isso é irrelevante para outros casos - como aquele para o qual estou aqui lang1.domain.com - lang2.domain.com
r --------- k
5

Definir como cookie no domínio principal -

document.cookie = "key=value;domain=.mydomain.com"

e, em seguida, pegue os dados de qualquer domínio principal ou subdomínio e defina-os no localStorage

URL87
fonte
0

Foi assim que resolvi para o meu site. Redirecionei todas as páginas sem www para www.site.com. Dessa forma, sempre levará o armazenamento local de www.site.com

Adicione o seguinte ao seu .htacess (crie um se ainda não tiver) no diretório raiz

RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
Ayush Baheti
fonte
5
Estou muito tentado a votar negativamente, mas não irei porque pode ajudar no caso de uso do OP, mas para pessoas que desejam manter sessões em myapp.com e developers.myapp.com e support.myapp.com, esta resposta é não é bom.
Don Omondi
hey @DonOmondi agradeceria se você pudesse me ajudar com os links para o que você está sugerindo!
Ayush Baheti
3
O OP perguntou "use localStorage em subdomínios" sua resposta é "redirecionar www para não-www" coisas muito diferentes, mas pode funcionar se e somente se o subdomínio específico for "www.abc.com" para casos gerais, algumas outras respostas aqui são mais prático.
Don Omondi
0

É assim:

Para compartilhar entre subdomínios de um determinado superdomínio (por exemplo, exemplo.com), existe uma técnica que você pode usar nessa situação. Pode ser aplicado para localStorage, IndexedDB, SharedWorker, BroadcastChannel, etc, todos os quais oferecem funcionalidade compartilhada entre as páginas de mesma origem, mas por alguma razão não respeitam qualquer modificaçãodocument.domain que iria deixá-los usar o superdomínio como sua origem diretamente.

(1) Escolha um domínio "principal" para os dados pertencerem: ou seja, https://example.com ou https://www.example.com manterá seus dados localStorage. Digamos que você escolha https://example.com .

(2) Use localStorage normalmente para as páginas do domínio escolhido.

(3) Em todas as páginas https://www.example.com (o outro domínio), use javascript para definir document.domain = "example.com";. Em seguida, crie também um oculto <iframe>e navegue até alguma página no domínio https://example.com escolhido ( não importa qual , contanto que você possa inserir um pequeno trecho de javascript nela. Se você ' Ao re-criar o site, basta fazer uma página vazia especificamente para este propósito. Se você estiver escrevendo uma extensão ou um script de usuário no estilo Greasemonkey e, portanto, não tiver nenhum controle sobre as páginas no example.com servidor de página , basta escolher a página mais leve que puder encontrar e inserir seu script nela. uma página "não encontrada" provavelmente seria adequada).

(4) O script na página oculta do iframe precisa apenas (a) definir document.domain = "example.com";e (b) notificar a janela pai quando isso for feito. Depois disso, a janela pai pode acessar a janela iframe e todos os seus objetos sem restrição! Portanto, a página iframe mínima é algo como:

<!doctype html>
<html>
<head>
  <script>
    document.domain = "example.com";
    window.parent.iframeReady();  // function defined & called on parent window
  </script>
</head>
<body></body>
</html>

Se estiver escrevendo um userscript, você pode não querer adicionar funções acessíveis externamente, como o iframeReady()seu unsafeWindow, então, em vez disso, a melhor maneira de notificar o userscript da janela principal pode ser usar um evento personalizado:

    window.parent.dispatchEvent(new CustomEvent("iframeReady"));

Que você detectaria adicionando um listener para o evento "iframeReady" personalizado à janela da página principal.

(Na verdade, eu escrevi esta resposta para o caso geral em que o domínio escolhido não é necessariamente o superdomínio example.com . Mas, como já está aqui , provavelmente nem precisamos definir document.domainno iframe - então a única coisa necessário é que a janela principal seja notificada quando o iframe estiver pronto para ser acessado).

(5) Uma vez que o escondido iframe informou sua janela pai que ele está pronto, roteiro na janela pai pode apenas usar iframe.contentWindow.localStorage, iframe.contentWindow.indexedDB, iframe.contentWindow.BroadcastChannel, iframe.contentWindow.SharedWorkerem vez de window.localStorage, window.indexedDB, etc. ... e todos estes objetos serão escopo para o escolhido https: // origem de example.com - então eles terão a mesma origem compartilhada para todas as suas páginas!

A parte mais complicada dessa técnica é que você precisa aguardar o carregamento do iframe antes de prosseguir. Portanto, você não pode simplesmente começar a usar localStorage em seu manipulador DOMContentLoaded, por exemplo. Além disso, você pode querer adicionar algum tratamento de erro para detectar se o iframe oculto falha ao carregar corretamente.

Obviamente, você também deve certificar-se de que o iframe oculto não seja removido ou navegado durante o tempo de vida da sua página ... OTOH Não sei qual seria o resultado disso, mas muito provavelmente coisas ruins aconteceriam.

E, uma advertência: a configuração / alteração document.domainpode ser bloqueada usando o Feature-Policycabeçalho, caso em que esta técnica não será utilizável conforme descrito.


No entanto, há uma generalização significativamente mais complicada dessa técnica, que não pode ser bloqueada por Feature-Policy, e que também permite que domínios totalmente não relacionados compartilhem dados, comunicações e trabalhos compartilhados (ou seja, não apenas subdomínios de um superdomínio comum). @Mayank Jain já o descreveu em sua resposta, a saber:

A ideia geral é que, assim como acima, você crie um iframe oculto para fornecer a origem correta para o acesso; mas em vez de apenas pegar as propriedades da janela do iframe diretamente, você usa o script dentro do iframe para fazer todo o trabalho e se comunica entre o iframe e sua janela principal usando apenas postMessage()e addEventListener("message",...).

Isso funciona porque postMessage()pode ser usado mesmo entre janelas de origens diferentes. Mas também é significativamente mais complicado porque você precisa passar tudo por algum tipo de infraestrutura de mensagens criada entre o iframe e a janela principal, em vez de apenas usar as APIs localStorage, IndexedDB etc. diretamente no código da janela principal.

Doin
fonte