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

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


person JoJo    schedule 26.10.2010    source источник
comment
Firefox и IE8 поддерживают хранение постоянных данных в домене, указанном пользователем. Например, на FF вы можете сделать globalStorage ['site.com'], и это будет возможно для www.site.com и site.com. Я до сих пор не понял, как это сделать в реализации Chrome.   -  person JoJo    schedule 27.10.2010
comment
Подумайте об использовании одного или последнего - перенаправьте всех пользователей, посещающих с www. поддомен к домену без поддомена, или наоборот.   -  person Elad Nava    schedule 19.01.2018
comment
Я давно создал статью: Cross-Domain LocalStorage   -  person jcubic    schedule 04.08.2020


Ответы (8)


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

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

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

person Mayank Jain    schedule 11.10.2011
comment
Это настоящий ответ, а не проверенный. Я сделал это сам, но также создал удобную оболочку обратного вызова с postMessage. - person King Friday; 26.07.2012
comment
Согласен с предыдущим комментатором. Это должно сработать. Но в основном это обходной путь :) Похоже, спецификация localStorage должна быть более гибкой. - person ValeriiVasin; 27.12.2012
comment
Этот метод позволяет передавать данные из любого домена в любой другой домен. Это обходной путь, как сказал InviS, и это не то же самое, что совместное использование одного и того же объекта локального хранилища на tld. - person oriadam; 26.10.2015
comment
Вот хорошая статья с примером кода, объясняющим этот метод: jcubic.wordpress .com / 2014/06/20 / cross-domain-localstorage - person Todd Price; 04.02.2016
comment
Обратите внимание, что это возможно только в том случае, если сторонние файлы cookie не отключены: stackoverflow.com/a/44097269/4311428 - person maxeh; 21.05.2017
comment
Чтобы заставить его работать с iframe и postMessage, вам нужно будет проверить, есть ли у URL-адреса www, а затем создать iframe без него, а если у него нет www, вы создаете iframe с www. страница может быть одинаковой для обоих URL. - person jcubic; 25.08.2017
comment
Apple обновила настройки по умолчанию в Safari 7+ как для настольных компьютеров, так и для мобильных устройств, чтобы заблокировать сторонние данные. Параметр теперь называется Блокировать файлы cookie и другие данные веб-сайта, который относится к таким вещам, как локальное хранилище, которые теперь полностью изолированы доменом. Этот метод не работает в Safari - person Aranganathan; 03.07.2018
comment
@Max @Aranganathan он по-прежнему работает для исходного случая вопроса - _1 _ / _ 2_, пока субдомены находятся в одном родительском домене - person Kostiantyn; 24.07.2019
comment
Это лучший ответ для общего случая совместного использования localStorage между двумя совершенно разными доменами. Однако, когда они связаны поддоменами, существует аналогичное, но НАМНОГО более простое решение, которое состоит в том, чтобы установить document.domain в одно и то же значение как в родительском окне, так и в iframe, а затем просто использовать объект iframe.contentWindow.localStorage вместо window.localstorage. Публикации сообщений можно избежать, потому что окна могут взаимодействовать напрямую. Это намного проще! - person Doin; 26.08.2020
comment
Итак, похоже, что postMessage с родительским iframe - это единственное решение - person Roman Grinev; 09.11.2020
comment
@Roman Да, похоже. Уведомление о том, что он устарел, новое - его не было 3 месяца назад, когда я писал. Это позор, потому что адаптация существующего кода, который использует localStorage или indexedDB для использования гораздо более ограниченного postMessage(), может часто потребовать полной и сложной перезаписи ... и в (общем) случае, когда все поддомены фактически являются частями одного и того же веб-сайт, проблемы безопасности, связанные с document.domain, не могут быть применены. - person Doin; 11.11.2020
comment
Хотя это решение и ответ на проблему, я бы добавил некоторую информацию о том, насколько это неортодоксально и что этого не следует делать вообще. - person azevik; 22.12.2020
comment
@azevik Можете ли вы объяснить, почему это решение неортодоксальное и его вообще не следует делать? - person Tom; 20.05.2021

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

Плюсы:

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

Минусы:

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

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

person Matt    schedule 22.01.2015
comment
Минус: максимальный размер файла cookie 4k - person Blake Miller; 02.04.2015
comment
Кроме того, как я узнал на собственном горьком опыте, предел в 4 КБ - это сумма размеров всех файлов cookie для одного домена, а не для каждого файла cookie. - person Blake Miller; 11.08.2015
comment
другие минусы: - файлы cookie с большей вероятностью будут заблокированы блокировщиками рекламы - файлы cookie предназначены для использования для обмена небольшими данными между сервером и клиентом, если сервер не использует данные, которые вы храните в файле cookie, это, следовательно, неправильное использование - person Enno; 27.12.2019
comment
Еще один минус: в таких браузерах, как Safari и Brave, файлы cookie, установленные из внешнего интерфейса, имеют максимальный срок службы 7 дней. - person Rishabh Poddar; 12.04.2021

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

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

person Eran Galperin    schedule 26.10.2010
comment
У меня нет доступа администратора к серверам для такого перенаправления. Позволяет ли эта библиотека обмениваться постоянными данными между www и без www? После некоторого чтения кажется, что почти все механизмы хранения браузеров не позволяют этого. Неважно, куки это или localStorage, мы столкнемся с этой проблемой ... - person JoJo; 27.10.2010
comment
Да, хранилище обычно зависит от домена, включая субдомен. Вот почему я предложил перенаправление. Вам не обязательно нужен доступ администратора, просто используйте правило .htaccess в корне документа. - person Eran Galperin; 27.10.2010
comment
@JoJo Есть несколько способов перенаправления, например отправив заголовок Location, или через <meta> тег HTML, или даже JS через window.location. - person Sony Santos; 26.06.2011
comment
Это просто уход от ответа. См. Ответ Mayank как правильный. - person King Friday; 26.07.2012
comment
+1 @avoiding, плюс это не имеет отношения к другим случаям - например, к тому, для которого я здесь lang1.domain.com - lang2.domain.com - person r---------k; 26.02.2015
comment
Вы можете сделать это с помощью JS: if (!/^www/.test(location.hostname)) location.href=location.href.replace('://','://www.') - person oriadam; 26.10.2015
comment
Пожалуйста, сделайте перенаправление с www.site.com на site.com, чтобы больше никогда не использовать субдомен www :) - person 3Dom; 06.03.2017

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

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

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

person URL87    schedule 13.01.2020
comment
тогда все почтовые запросы будут открыты для CSRF-атаки. - person Murat Tutumlu; 14.01.2021

Вот как:

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

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

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

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

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

(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 и т. Д. Непосредственно в коде вашего главного окна.

person Doin    schedule 26.08.2020

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

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

person biology.info    schedule 10.12.2015
comment
Я посмотрел на него, но похоже, что он не работает в Safari. github.com/ofirdagan/cross-domain-local-storage/issues/ 10 - person Andris Zalitis; 21.04.2016

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

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

RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
person Ayush Baheti    schedule 22.03.2017
comment
Мне очень хочется проголосовать против этого, но я не буду, потому что это может помочь варианту использования OP, но для людей, которые хотят поддерживать сеансы через myapp.com и developers.myapp.com и support.myapp.com, этот ответ фигово. - person Don Omondi; 17.10.2017
comment
привет @DonOmondi, я был бы признателен, если бы вы помогли мне со ссылками на то, что вы предлагаете! - person Ayush Baheti; 04.12.2017
comment
OP попросил использовать localStorage между поддоменами, ваш ответ перенаправляет www на не-www очень разные вещи, но он может работать тогда и только тогда, когда конкретным поддоменом является www.abc.com, для общих случаев некоторые другие ответы здесь более практичны. - person Don Omondi; 05.12.2017

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

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

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

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

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

person Jamil Noyda    schedule 16.04.2020