użyj localStorage w subdomenach

98

Zamieniam pliki cookie na localStorage w przeglądarkach, które mogą to obsługiwać (każdy oprócz IE). Problem dotyczy witryny.com i www . site.com przechowują własne oddzielne obiekty localStorage . Uważam, że www jest uważane za subdomenę (głupia decyzja, jeśli o mnie chodzi). Jeśli użytkownik był pierwotnie na site.com i zdecydował się wpisać www . site.com podczas jej następnej wizyty wszystkie jej dane osobowe będą niedostępne. Jak sprawić, by wszystkie moje „subdomeny” korzystały z tego samego lokalnego magazynu, co domena główna?

JoJo
źródło
4
Firefox i IE8 obsługują przechowywanie trwałych danych w domenie określonej przez użytkownika. Na przykład na FF możesz zrobić globalStorage ['site.com'] i będzie to możliwe dla www.site.com i site.com. Nadal nie wiem, jak to zrobić w implementacji Chrome.
JoJo
9
Rozważ użycie jednego lub drugiego - przekieruj wszystkich użytkowników odwiedzających witrynę www. subdomena do domeny bez subdomeny lub odwrotnie.
Elad Nava,
Stworzyłem artykuł dawno temu: Cross-Domain LocalStorage
jcubic

Odpowiedzi:

96

W ten sposób używam go w różnych domenach ...

  • Użyj elementu iframe z domeny nadrzędnej - powiedz na przykład parent.com
  • Następnie w każdej domenie child.com wyślij wiadomość postMessage do elementu iframe parent.com
  • Wszystko, co musisz zrobić, to skonfigurować protokół interpretowania wiadomości postMessage, aby rozmawiać z iframe parent.com.

Mam nadzieję, że to pomoże :)

Mayank Jain
źródło
2
To jest prawdziwa odpowiedź, a nie ta odznaczona. Zrobiłem to sam, ale stworzyłem również wygodne opakowanie wywołania zwrotnego z postMessage.
Jason Sebring,
4
Oto dobry artykuł z przykładowym kodem wyjaśniającym tę metodę: jcubic.wordpress.com/2014/06/20/cross-domain-localstorage
Todd Price,
4
Pamiętaj, że jest to możliwe tylko wtedy, gdy pliki cookie innych firm nie są wyłączone: stackoverflow.com/a/44097269/4311428
maxeh
6
Firma Apple zaktualizowała ustawienia domyślne w Safari 7+ zarówno na komputerach stacjonarnych, jak i mobilnych, aby zablokować dane innych firm. Ta opcja nazywa się teraz „Blokuj pliki cookie i inne dane witryn” i odnosi się do takich rzeczy, jak lokalne przechowywanie, które jest teraz całkowicie izolowane przez domenę. Ta metoda nie zadziała w Safari
Aranganathan,
2
@Max @Aranganathan nadal działa w przypadku oryginalnego pytania - site.com/ www.site.como ile subdomeny znajdują się w tej samej domenie nadrzędnej
Kostiantyn
41

Jeśli używasz rozwiązania iframe i postMessage tylko dla tego konkretnego problemu, myślę, że może być mniej pracy (zarówno pod względem kodu, jak i obliczeń), aby po prostu przechowywać dane w pliku cookie bez subdomeny, a jeśli jeszcze nie jest w localStorage podczas ładowania, pobierz go z pliku cookie .

Plusy:

  • Nie wymaga dodatkowej konfiguracji iframe i postMessage.

Cons:

  • Udostępni dane we wszystkich subdomenach (nie tylko www), więc jeśli nie ufasz wszystkim subdomenom, może to nie działać dla Ciebie.
  • Wyśle dane do serwera na każde żądanie. Niezbyt dobre, ale w zależności od scenariusza może nadal wymagać mniej pracy niż rozwiązanie iframe / postMessage.
  • Jeśli to robisz, dlaczego nie używać bezpośrednio plików cookie? Zależy od kontekstu.
  • Maksymalny rozmiar pliku cookie 4K, łącznie dla wszystkich plików cookie w domenie (dzięki Blake'owi za wskazanie tego w komentarzach)

Zgadzam się jednak z innymi komentatorami, wydaje się, że powinna to być opcja do określenia dla localStorage, więc obejścia nie są wymagane.

Matt
źródło
31
Wada: maksymalny rozmiar pliku cookie 4k
Blake Miller
18
Ponadto, jak się przekonałem, limit 4k dotyczy sumy rozmiarów wszystkich plików cookie dla jednej domeny, a nie dla każdego pliku cookie.
Blake Miller,
inne wady: - pliki cookie będą prawdopodobnie blokowane przez adblockery - pliki cookie są przeznaczone do udostępniania małych danych między serwerem a klientem, jeśli serwer nie wykorzystuje danych przechowywanych w pliku cookie, jest to w konsekwencji nadużycie
Enno
33

Proponuję przekierować site.com do www.site.com zarówno dla spójności, jak i uniknięcia takich problemów.

Rozważ również użycie rozwiązania obsługującego wiele przeglądarek, takiego jak PersistJS, które może korzystać z natywnego magazynu każdej przeglądarki.

Eran Galperin
źródło
Nie mam dostępu administratora do serwerów, aby wykonać takie przekierowanie. Czy ta biblioteka pozwala mi na udostępnianie trwałych danych między www i bez www? Po przeczytaniu wydaje się, że prawie wszystkie mechanizmy przechowywania przeglądarki na to nie pozwalają. Bez względu na to, czy są to pliki cookie, czy localStorage, napotkamy ten problem ...
JoJo
Tak, pamięć jest zwykle zależna od domeny, w tym od subdomeny. Dlatego zasugerowałem przekierowanie. Nie musisz koniecznie mieć dostępu administratora, po prostu użyj reguły .htaccess w katalogu głównym dokumentu
Eran Galperin
1
@JoJo Istnieje kilka sposobów na przekierowanie, np. Poprzez wysłanie nagłówka Location, poprzez <meta>znacznik HTML lub nawet JS przez window.location.
Sony Santos
1
To po prostu unikanie odpowiedzi. Zobacz odpowiedź Mayanka jako poprawną.
Jason Sebring,
1
+1 @ unikanie, a ponadto nie ma to znaczenia w innych przypadkach - na przykład w tym, w którym tu jestem lang1.domain.com - lang2.domain.com
r --------- k
11

Ustawiony na plik cookie w domenie głównej -

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

a następnie pobierz dane z dowolnej domeny głównej lub subdomeny i umieść je w localStorage

URL87
źródło
2

Oto jak:

W przypadku udostępniania między subdomenami danej superdomeny (np. Example.com), istnieje technika, której możesz użyć w takiej sytuacji. Może być stosowany do localStorage, IndexedDB, SharedWorker, BroadcastChannel, itp, z których wszystkie oferują wspólną funkcjonalność między stronami tego samego pochodzenia, ale z jakiegoś powodu nie przestrzegają żadnych modyfikacji document.domain, które pozwoli im korzystać z naddomenę ich pochodzenia bezpośrednio.

(1) Wybierz jedną „główną” domenę, do której mają należeć dane: tj. Https://example.com lub https://www.example.com będzie przechowywać dane localStorage. Załóżmy, że wybierasz https://example.com .

(2) Normalnie używaj localStorage dla stron wybranej domeny.

(3) Na wszystkich stronach https://www.example.com ( inna domena) użyj javascript do ustawienia document.domain = "example.com";. Następnie utwórz także ukrytą <iframe>i przejdź do jakiejś strony w wybranej domenie https://example.com ( nie ma znaczenia, która strona , o ile możesz wstawić tam bardzo mały fragment kodu JavaScript. Jeśli „ ponownego tworzenia witryny, po prostu utwórz pustą stronę specjalnie w tym celu. Jeśli piszesz rozszerzenie lub skrypt użytkownika w stylu Greasemonkey, a więc nie masz żadnej kontroli nad stronami w witrynie example.comserwer, po prostu wybierz najlżejszą stronę, jaką możesz znaleźć i wstaw do niej swój skrypt. Jakaś strona „nie znaleziono” prawdopodobnie byłaby w porządku).

(4) Skrypt na ukrytej stronie iframe musi tylko (a) ustawić document.domain = "example.com";i (b) powiadomić okno nadrzędne, kiedy to się stanie. Następnie okno nadrzędne może uzyskać dostęp do okna iframe i wszystkich jego obiektów bez ograniczeń! Zatem minimalna strona iframe wygląda mniej więcej tak:

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

Pisząc skrypt użytkownika, możesz nie chcieć dodawać funkcji dostępnych z zewnątrz, takich jak iframeReady()twój unsafeWindow, więc zamiast tego lepszym sposobem powiadomienia skryptu użytkownika okna głównego może być użycie zdarzenia niestandardowego:

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

Które można wykryć, dodając detektor dla niestandardowego zdarzenia „iframeReady” do okna strony głównej.

(UWAGA: musisz ustawić document.domain = "example.com", nawet jeśli domena iframe to już example.com : przypisanie wartości do document.domain niejawnie ustawia port pochodzenia na null, a oba porty muszą pasować do elementu iframe i jego rodzica są uważane za tego samego pochodzenia. Zobacz uwagę tutaj: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin )

(5) Po ukryte iframe poinformował swojego okna nadrzędnego, że jest gotowy, skrypt w oknie nadrzędnym może po prostu użyć iframe.contentWindow.localStorage, iframe.contentWindow.indexedDB, iframe.contentWindow.BroadcastChannel, iframe.contentWindow.SharedWorkerzamiast window.localStorage, window.indexedDBitd ... i wszystkie te obiekty zostaną scoped na wybrany https: // example.com origin - dzięki czemu będą miały to samo wspólne źródło dla wszystkich Twoich stron!

Najbardziej niewygodną częścią tej techniki jest to, że przed kontynuowaniem musisz poczekać na załadowanie elementu iframe. Nie możesz więc po prostu beztrosko zacząć używać localStorage na przykład w module obsługi DOMContentLoaded. Możesz także dodać obsługę błędów, aby wykryć, czy ukryta ramka iframe nie ładuje się poprawnie.

Oczywiście powinieneś również upewnić się, że ukryta ramka iframe nie jest usuwana ani nawigowana przez cały czas istnienia Twojej strony ... OTOH Nie wiem, jaki byłby tego skutek, ale bardzo prawdopodobne, że wydarzy się coś złego.

I zastrzeżenie: ustawianie / zmienianie document.domainmożna zablokować za pomocą Feature-Policynagłówka, w takim przypadku ta technika nie będzie użyteczna zgodnie z opisem.


Istnieje jednak znacznie bardziej skomplikowane uogólnienie tej techniki, którego nie można zablokować Feature-Policy, a także umożliwia całkowicie niepowiązanym domenom udostępnianie danych, komunikacji i współdzielonych pracowników (tj. Nie tylko subdomen ze wspólnej superdomeny). @Mayank Jain opisał to już w swojej odpowiedzi, a mianowicie:

Ogólna idea jest taka, że ​​tak jak powyżej, tworzysz ukrytą ramkę iframe, aby zapewnić prawidłowe źródło dostępu; ale zamiast po prostu pobierać bezpośrednio właściwości okna iframe, używasz skryptu wewnątrz elementu iframe, aby wykonać całą pracę, i komunikujesz się między elementem iframe a oknem głównym tylko za pomocą postMessage()i addEventListener("message",...).

To działa, ponieważ postMessage()można go używać nawet między oknami różnych źródeł. Ale jest to również znacznie bardziej skomplikowane, ponieważ musisz przepuścić wszystko przez jakąś infrastrukturę komunikacyjną, którą tworzysz między ramką iframe a oknem głównym, zamiast po prostu używać interfejsów API localStorage, IndexedDB itp. Bezpośrednio w kodzie głównego okna.

Doin
źródło
0

W ten sposób rozwiązałem to dla mojej strony internetowej. Przekierowałem wszystkie strony bez www na www.site.com. W ten sposób zawsze zajmie lokalne przechowywanie z www.site.com

Dodaj następujący plik do swojego .htacess (utwórz go, jeśli jeszcze go nie masz) w katalogu głównym

RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
Ayush Baheti
źródło
6
Bardzo kusi mnie, by to zlekceważyć, ale nie zrobię tego, ponieważ może to pomóc w przypadku użycia OP, ale dla osób, które chcą utrzymywać sesje na myapp.com i developers.myapp.com i support.myapp.com, ta odpowiedź brzmi niedobrze.
Don Omondi
hej @DonOmondi Byłbym wdzięczny, gdybyś mógł mi pomóc z linkami do tego, co sugerujesz!
Ayush Baheti
3
OP zapytał „użyj localStorage w subdomenach” Twoja odpowiedź brzmi „przekieruj www na inny niż www” bardzo różne rzeczy, ale może to zadziałać wtedy i tylko wtedy, gdy konkretna subdomena to „www.abc.com” w ogólnych przypadkach. bardziej praktyczne.
Don Omondi