É 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.domain
no 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.SharedWorker
em 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.domain
pode ser bloqueada usando o Feature-Policy
cabeç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.