использовать localStorage в поддоменах


102

Я заменяю файлы cookie на localStorage в браузерах, которые могут его поддерживать (кто угодно, кроме IE). Проблема в site.com и www . site.com хранят свои собственные отдельные объекты localStorage. Я считаю, что www считается субдоменом (глупое решение, если вы спросите меня). Если пользователь изначально был на site.com и решил ввести www . site.com при ее следующем посещении все ее личные данные будут недоступны. Как мне сделать так, чтобы все мои «поддомены» использовали тот же localStorage, что и основной домен?


4
Firefox и IE8 поддерживают хранение постоянных данных в домене, указанном пользователем. Например, на FF вы можете сделать globalStorage ['site.com'], и это будет возможно для www.site.com и site.com. Я до сих пор не понял, как это сделать в реализации Chrome.
JoJo

9
Рассмотрите возможность использования одного или последнего - перенаправьте всех пользователей, посещающих с www. поддомен в домен без поддомена, или наоборот.
Elad Nava

1
Я давно создал статью: Cross-Domain LocalStorage
jcubic

Ответы:


97

Вот как я использую его в разных доменах ...

  • Используйте iframe из родительского домена - скажем, parent.com
  • Затем на каждом домене child.com просто сделайте postMessage в iframe вашего parent.com
  • Все, что вам нужно сделать, это настроить протокол того, как интерпретировать сообщения postMessage для взаимодействия с iframe parent.com.

Я надеюсь, что это помогает :)


2
Это настоящий ответ, а не проверенный. Я сделал это сам, но также создал удобную оболочку обратного вызова с postMessage.
Джейсон Себринг,

4
Вот хорошая статья с примерами кода, объясняющими этот метод: jcubic.wordpress.com/2014/06/20/cross-domain-localstorage
Тодд Прайс

4
Обратите внимание, что это возможно только в том случае, если сторонние файлы cookie не отключены: stackoverflow.com/a/44097269/4311428
maxeh

6
Apple обновила настройки по умолчанию в Safari 7+ как для настольных компьютеров, так и для мобильных устройств, чтобы заблокировать сторонние данные. Параметр теперь называется «Блокировать файлы cookie и другие данные веб-сайта» и относится к таким вещам, как локальное хранилище, которые теперь полностью изолированы доменом. Этот метод не будет работать в Safari
Аранганатан

2
@Max @Aranganathan, он по-прежнему работает для исходного случая вопроса - site.com/ www.site.comпока субдомены находятся в одном родительском домене
Константин

43

Если вы используете решение iframe и postMessage только для этой конкретной проблемы, я думаю, что может быть меньше работы (как с точки зрения кода, так и с точки зрения вычислений), чтобы просто сохранить данные в файле cookie без поддомена, и, если он еще не в localStorage при загрузке возьмите его из файла cookie .

Плюсы:

  • Не требует дополнительной настройки iframe и postMessage.

Минусы:

  • Сделает данные доступными для всех поддоменов (не только www), поэтому, если вы не доверяете всем поддоменам, это может не сработать для вас.
  • Будет отправлять данные на сервер при каждом запросе. Не очень хорошо, но в зависимости от вашего сценария, может быть, все еще меньше работы, чем решение iframe / postMessage.
  • Если вы это делаете, почему бы просто не использовать файлы cookie напрямую? Зависит от вашего контекста.
  • Максимальный размер файла cookie 4K, общий для всех файлов cookie для домена (спасибо Блейку за указание на это в комментариях)

Я согласен с другими комментаторами, похоже, что это должна быть конкретная опция для localStorage, поэтому обходные пути не требуются.


32
Con: Максимальный размер файла cookie 4k
Блейк Миллер

18
Кроме того, как я узнал на собственном горьком опыте, предел в 4 КБ - это сумма размеров всех файлов cookie для одного домена, а не для каждого файла cookie.
Блейк Миллер

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

33

Я предлагаю сделать переадресацию site.com на www.site.com как для единообразия, так и для предотвращения подобных проблем.

Также рассмотрите возможность использования кросс-браузерного решения, такого как PersistJS, которое может использовать каждое собственное хранилище браузера.


У меня нет доступа администратора к серверам для такого перенаправления. Позволяет ли эта библиотека обмениваться постоянными данными между www и без www? После некоторого чтения кажется, что почти все механизмы хранения браузеров не позволяют этого. Неважно, куки это или localStorage, мы столкнемся с этой проблемой ...
JoJo

Да, хранилище обычно зависит от домена, включая субдомен. Вот почему я предложил перенаправление. Вам не обязательно нужен доступ администратора, просто используйте правило .htaccess в корне документа
Эран Гальперин,

1
@JoJo Существует несколько способов перенаправления, например, путем отправки заголовка Location, через <meta>тег HTML или даже через JS window.location.
Sony Santos,

1
Это просто уход от ответа. См. Ответ Mayank как правильный.
Джейсон Себринг,

1
+1 @avoiding, плюс это не имеет значения для других случаев - например, тот, для которого я здесь lang1.domain.com - lang2.domain.com
r --------- k

11

Установить cookie в основном домене -

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

а затем возьмите данные из любого основного домена или поддомена и установите их в localStorage


4

Я использую xdLocalStorage, это легкая js-библиотека, которая реализует интерфейс LocalStorage и поддерживает междоменное хранилище с помощью сообщений сообщений iframe post. (Поддержка angularJS)

https://github.com/ofirdagan/cross-domain-local-storage


3
Я посмотрел на него, но похоже, что он не работает в Safari. github.com/ofirdagan/cross-domain-local-storage/issues/10
Андрис Залитис

2

Вот как:

[ Обновление за ноябрь 2020 г .: это решение зависит от возможности установить document.domain. К сожалению, такая возможность устарела. ]

Для обмена между поддоменами данного супердомена (например, example.com) есть метод, который вы можете использовать в этой ситуации. Он может быть применен к localStorage, IndexedDB,SharedWorker , BroadcastChannelи т.д., все из которых имеют общую функциональность между же происхождения страниц, но по какой - то причине не соблюдают никаких изменений, document.domainкоторые позволили бы им использовать супердомена как их происхождение непосредственно.

(1) Выберите один «основной» домен, к которому будут принадлежать данные: например, https://example.com или https://www.example.com. которому будут будет содержать ваши данные localStorage. Допустим, вы выбрали https://example.com .

(2) Обычно используйте localStorage для страниц выбранного домена.

(3) На всех страницах https://www.example.com ( другой домен) используйте javascript для установкиdocument.domain = "example.com"; . Затем также создайте скрытый <iframe>и перейдите на какую-либо страницу в выбранном домене https://example.com ( неважно, на какой странице , если вы можете вставить туда очень маленький фрагмент javascript. Если вы при повторном создании сайта просто создайте пустую страницу специально для этой цели. Если вы пишете расширение или пользовательский скрипт в стиле Greasemonkey и не имеете никакого контроля над страницами на example.comserver, просто выберите самую легкую из возможных страниц и вставьте на нее свой скрипт. Возможно, подойдет какая-то страница "не найдена").

(4) Скрипт на скрытой странице iframe нужно только (а) установить document.domain = "example.com";и (б) уведомить родительское окно, когда это будет сделано. После этого родительское окно может получить доступ к окну iframe и всем его объектам без ограничений! Итак, минимальная страница iframe выглядит примерно так:

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

При написании пользовательского скрипта вы, возможно, не захотите добавлять функции, доступные извне, такие как iframeReady()ваш unsafeWindow, поэтому вместо этого лучшим способом уведомить пользовательский скрипт главного окна может быть использование настраиваемого события:

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

Это можно обнаружить, добавив слушателя для пользовательского события iframeReady в окно главной страницы.

(ПРИМЕЧАНИЕ: вам необходимо установить document.domain = "example.com", даже если домен iframe уже example.com : присвоение значения document.domain неявно устанавливает для порта источника значение null, и оба порта должны совпадать для iframe. и его родительский элемент должен рассматриваться как тот же источник. См. примечание здесь: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin )

(5) После того , как скрытый IFrame сообщил его родительское окно , что он готов, сценарий в родительском окне можно просто использовать iframe.contentWindow.localStorage, iframe.contentWindow.indexedDB, iframe.contentWindow.BroadcastChannel, iframe.contentWindow.SharedWorkerвместо того window.localStorage,window.indexedDB и т.д. ... и все эти объекты будут область видимости выбранной https: // example.com origin - так что у них будет одно и то же общее происхождение для всех ваших страниц!

Самая неудобная часть этого метода заключается в том, что вам нужно дождаться загрузки iframe, прежде чем продолжить. Таким образом, вы не можете просто беспечно начать использовать localStorage в своем обработчике DOMContentLoaded, например. Также вы можете добавить некоторую обработку ошибок, чтобы определить, не загружается ли скрытый iframe правильно.

Очевидно, вы также должны убедиться, что скрытый iframe не удаляется или не перемещается в течение всего срока службы вашей страницы ... OTOH Я не знаю, каков будет результат, но очень вероятно, что произойдет что-то плохое.

И предостережение: настройку / изменение document.domainможно заблокировать с помощью Feature-Policyзаголовка, и в этом случае этот метод нельзя будет использовать, как описано.


Однако существует значительно более сложное обобщение этого метода, которое не может быть заблокировано Feature-Policy, и которое также позволяет совершенно несвязанным доменам обмениваться данными, коммуникациями и совместно используемыми рабочими (т.е. не только поддоменами из общего супердомена). @Mayank Jain уже описал это в своем ответе, а именно:

Общая идея заключается в том, что, как и выше, вы создаете скрытый iframe, чтобы обеспечить правильное происхождение для доступа; но вместо того, чтобы напрямую захватывать свойства окна iframe, вы используете сценарий внутри iframe для выполнения всей работы, и вы общаетесь между iframe и вашим главным окном, используя только postMessage()иaddEventListener("message",...) .

Это работает, потому что postMessage()может использоваться даже между окнами разного происхождения. Но это также значительно сложнее, потому что вам нужно передать все через какую-то инфраструктуру обмена сообщениями, которую вы создаете между iframe и главным окном, а не просто использовать API localStorage, IndexedDB и т. Д. Непосредственно в коде вашего главного окна.


1

такое решение вызывает множество подобных проблем. по соображениям согласованности и SEO перенаправление на основной домен - лучшее решение.

сделать это перенаправление на уровне сервера

Как перенаправить www на не-www с помощью Nginx

https://www.digitalocean.com/community/tutorials/how-to-redirect-www-to-non-www-with-nginx-on-centos-7

или любой другой уровень, например маршрут 53, если вы используете


0

Вот как я решил это для своего сайта. Я перенаправил все страницы без www на www.site.com. Таким образом, всегда будет использоваться локальное хранилище www.site.com.

Добавьте следующее в свой .htacess (создайте его, если у вас его еще нет) в корневом каталоге

RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]

6
Мне очень хочется проголосовать против этого, но я не буду, потому что это может помочь варианту использования OP, но для людей, которые хотят поддерживать сеансы через myapp.com и developers.myapp.com и support.myapp.com, этот ответ фигово.
Дон

привет @DonOmondi, я был бы признателен, если бы вы помогли мне со ссылками на то, что вы предлагаете!
Ayush Baheti

3
OP попросил «использовать localStorage между поддоменами», ваш ответ - «перенаправить www на не-www», очень разные вещи, но он может работать тогда и только тогда, когда конкретный поддомен «www.abc.com» для общих случаев, некоторые другие ответы здесь более практичным.
Don
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.