ใช้ localStorage ข้ามโดเมนย่อย


101

ฉันกำลังแทนที่คุกกี้ด้วย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 ของคุณเพื่อพูดคุยกับ parent.com iframe

ฉันหวังว่ามันจะช่วย :)


2
นี่คือคำตอบที่แท้จริงไม่ใช่คำตอบที่ถูกเลือก ฉันได้ทำสิ่งนี้ด้วยตัวเองแล้ว แต่ยังสร้าง callback wrapper ที่สะดวกด้วย postMessage
Jason Sebring

4
นี่คือบทความดีๆพร้อมโค้ดตัวอย่างที่อธิบายวิธีการนี้: jcubic.wordpress.com/2014/06/20/cross-domain-localstorage
Todd Price

4
โปรดทราบว่าจะทำได้ก็ต่อเมื่อไม่ได้ปิดใช้งานคุกกี้ของบุคคลที่สาม: stackoverflow.com/a/44097269/4311428
maxeh

6
Apple ได้อัปเดตค่าเริ่มต้นบน Safari 7+ ทั้งบนเดสก์ท็อปและมือถือเพื่อบล็อกข้อมูลของบุคคลที่สาม ปัจจุบันตัวเลือกนี้เรียกว่า "บล็อกคุกกี้และข้อมูลเว็บไซต์อื่น ๆ " ซึ่งหมายถึงสิ่งต่างๆเช่นที่เก็บข้อมูลในเครื่องซึ่งปัจจุบันแยกตามโดเมนโดยสิ้นเชิง วิธีนี้จะใช้ไม่ได้ใน Safari
Aranganathan

2
@Max @Aranganathan ยังคงใช้ได้กับกรณีคำถามเดิม - site.com/ www.site.comตราบใดที่โดเมนย่อยอยู่บนโดเมนหลักเดียวกัน
Kostiantyn

42

หากคุณใช้โซลูชัน iframe และ postMessage สำหรับปัญหานี้โดยเฉพาะฉันคิดว่ามันอาจจะใช้งานได้น้อยกว่า (ทั้งที่ใช้โค้ดอย่างชาญฉลาดและฉลาดในการคำนวณ) ในการจัดเก็บข้อมูลในคุกกี้ที่ไม่มีโดเมนย่อยและหากยังไม่ได้ทำ ใน localStorage ในการโหลดคว้าได้จากคุกกี้

ข้อดี:

  • ไม่จำเป็นต้องตั้งค่า iframe และ postMessage เพิ่มเติม

จุดด้อย:

  • จะทำให้ข้อมูลพร้อมใช้งานในโดเมนย่อยทั้งหมด (ไม่ใช่แค่ www) ดังนั้นหากคุณไม่เชื่อถือโดเมนย่อยทั้งหมดก็อาจไม่ได้ผลสำหรับคุณ
  • จะส่งข้อมูลไปยังเซิร์ฟเวอร์ในแต่ละคำขอ ไม่ดี แต่ขึ้นอยู่กับสถานการณ์ของคุณอาจยังใช้งานได้น้อยกว่าโซลูชัน iframe / postMessage
  • หากคุณกำลังทำสิ่งนี้ทำไมไม่ใช้คุกกี้โดยตรง ขึ้นอยู่กับบริบทของคุณ
  • ขนาดคุกกี้สูงสุด 4K รวมจากคุกกี้ทั้งหมดสำหรับโดเมน (ขอบคุณ Blake ที่ชี้ให้เห็นในความคิดเห็น)

ฉันเห็นด้วยกับผู้แสดงความคิดเห็นคนอื่น ๆ ดูเหมือนว่าควรเป็นตัวเลือกที่ระบุได้สำหรับ localStorage ดังนั้นจึงไม่จำเป็นต้องมีการแก้ไข


32
Con: ขนาดคุกกี้สูงสุด 4k
Blake Miller

18
นอกจากนี้ฉันได้เรียนรู้วิธีที่ยากแล้วขีด จำกัด 4k คือผลรวมของขนาดของคุกกี้ทั้งหมดสำหรับโดเมนเดียวไม่ใช่สำหรับคุกกี้แต่ละรายการ
Blake Miller

ข้อเสียอื่น ๆ : - คุกกี้มีแนวโน้มที่จะถูกบล็อกโดย adblockers มากขึ้น - คุกกี้ถูกใช้เพื่อแบ่งปันข้อมูลขนาดเล็กระหว่างเซิร์ฟเวอร์และไคลเอนต์หากเซิร์ฟเวอร์ไม่ได้ใช้ข้อมูลที่คุณเก็บไว้ในคุกกี้จึงถือเป็นการใช้ในทางที่ผิด
Enno

33

ฉันขอแนะนำให้เปลี่ยนเส้นทาง site.com ไปที่ www.site.com เพื่อความสอดคล้องและเพื่อหลีกเลี่ยงปัญหาเช่นนี้

นอกจากนี้ให้พิจารณาใช้โซลูชันข้ามเบราว์เซอร์เช่นPersistJSที่สามารถใช้ที่เก็บข้อมูลเนทีฟของเบราว์เซอร์แต่ละตัวได้


ฉันไม่มีสิทธิ์เข้าถึงเซิร์ฟเวอร์ของผู้ดูแลระบบเพื่อทำการเปลี่ยนเส้นทาง ไลบรารีนั้นอนุญาตให้ฉันแบ่งปันข้อมูลถาวรระหว่าง www และไม่มี www หรือไม่ หลังจากอ่านไปแล้วดูเหมือนว่ากลไกการจัดเก็บข้อมูลเกือบทั้งหมดของเบราว์เซอร์ไม่อนุญาต ไม่ว่าจะเป็นคุกกี้หรือ localStorage เราจะพบกับปัญหานี้ ...
JoJo

ใช่โดยปกติพื้นที่เก็บข้อมูลจะขึ้นอยู่กับโดเมนรวมถึงโดเมนย่อยด้วย นี่คือเหตุผลที่ฉันแนะนำให้เปลี่ยนเส้นทาง คุณไม่จำเป็นต้องมีการเข้าถึงระดับผู้ดูแลระบบเพียงแค่ใช้กฎ. htaccess ในรูทเอกสาร
Eran Galperin

1
@JoJo มีหลายวิธีที่จะเปลี่ยนเส้นทางเช่นโดยการส่งส่วนหัวที่มีLocationหรือผ่าน<meta>แท็กหรือแม้กระทั่ง JS window.locationผ่าน
Sony Santos

1
นี่เป็นเพียงการหลีกเลี่ยงคำตอบ ดูคำตอบของ Mayank ว่าถูกต้อง
Jason Sebring

1
+1 @avoiding บวกนี้ไม่เกี่ยวข้องกับกรณีอื่น ๆ เช่นกรณีที่ฉันอยู่ที่นี่ lang1.domain.com - lang2.domain.com
r --------- k

11

ตั้งค่าเป็นคุกกี้ในโดเมนหลัก -

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

จากนั้นนำข้อมูลจากโดเมนหลักหรือโดเมนย่อยและตั้งค่าใน localStorage


4

ฉันใช้ xdLocalStorage นี่คือไลบรารี js ที่มีน้ำหนักเบาซึ่งใช้อินเทอร์เฟซ LocalStorage และรองรับการจัดเก็บข้อมูลข้ามโดเมนโดยใช้การสื่อสารข้อความโพสต์ iframe (รองรับ angularJS)

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


3
ฉันมองไปที่มัน แต่ดูเหมือนว่าจะไม่ทำงานบน Safari github.com/ofirdagan/cross-domain-local-storage/issues/10
Andris Zalitis

2

นี่คือวิธี:

[ พฤศจิกายน 2020 ปรับปรุง: การแก้ปัญหานี้ต้องอาศัยความสามารถในการตั้งค่า document.domainความสามารถในการดำเนินการดังกล่าวได้ถูกยกเลิกไปแล้วอย่างน่าเสียดาย ]

สำหรับการแชร์ระหว่างโดเมนย่อยของ superdomain ที่กำหนด (เช่น example.com) มีเทคนิคที่คุณสามารถใช้ในสถานการณ์นั้นได้ มันสามารถนำไปใช้localStorage, IndexedDB, SharedWorker, BroadcastChannelฯลฯ ซึ่งทั้งหมดนี้มีฟังก์ชันการทำงานร่วมกันระหว่างหน้าเดียวกันกำเนิด แต่ด้วยเหตุผลบางอย่างไม่เคารพการปรับเปลี่ยนใด ๆ เพื่อdocument.domainที่จะให้พวกเขาใช้ superdomain เป็นแหล่งกำเนิดของพวกเขาโดยตรง

(1) เลือกโดเมน "หลัก" หนึ่งโดเมนเพื่อให้ข้อมูลเป็นของ: เช่นhttps://example.comหรือhttps://www.example.comจะเก็บข้อมูล localStorage ของคุณ สมมติว่าคุณเลือกhttps://example.com

(2) ใช้ localStorage ตามปกติสำหรับเพจของโดเมนที่เลือกนั้น

(3) ในทุกhttps://www.example.comหน้า (คนอื่น ๆโดเมน) document.domain = "example.com";การใช้งานจาวาสคริปต์เพื่อชุด แล้วยังสร้างที่ซ่อนอยู่<iframe>และนำทางไปยังบางหน้าได้รับการแต่งตั้งhttps://example.comโดเมน ( มันไม่สำคัญว่าสิ่งที่หน้าตราบใดที่คุณสามารถแทรกตัวอย่างน้อยมากของ JavaScript บนมี. ถ้าคุณ' กำลังสร้างไซต์เพียงแค่สร้างหน้าว่างโดยเฉพาะเพื่อจุดประสงค์นี้หากคุณกำลังเขียนส่วนขยายหรือผู้ใช้แบบ Greasemonkey และไม่มีการควบคุมหน้าใด ๆ บนexample.comเซิร์ฟเวอร์เพียงเลือกหน้าที่มีน้ำหนักเบาที่สุดที่คุณสามารถค้นหาและแทรกสคริปต์ของคุณลงในนั้น หน้า "ไม่พบ" บางประเภทก็น่าจะใช้ได้)

(4) สคริปต์บนเพจ iframe ที่ซ่อนอยู่ต้องการเพียง (a) set document.domain = "example.com";และ (b) แจ้งหน้าต่างหลักเมื่อเสร็จสิ้น หลังจากนั้นหน้าต่างหลักสามารถเข้าถึงหน้าต่าง 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>

หากเขียน userscript คุณอาจไม่ต้องการเพิ่มฟังก์ชันที่เข้าถึงได้จากภายนอกเช่นในiframeReady()ของคุณunsafeWindowดังนั้นวิธีที่ดีกว่าในการแจ้ง userscript ของหน้าต่างหลักอาจเป็นการใช้เหตุการณ์ที่กำหนดเอง:

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

ซึ่งคุณจะตรวจพบได้โดยการเพิ่ม Listener สำหรับเหตุการณ์ "iframeReady" ที่กำหนดเองในหน้าต่างหน้าหลัก

(หมายเหตุ: คุณต้องตั้งค่า document.domain = "example.com" แม้ว่าโดเมนของ iframe จะเป็นexample.comอยู่แล้วก็ตาม: การกำหนดค่าให้กับ document.domain โดยปริยายจะตั้งค่าพอร์ตของต้นทางเป็นค่าว่างและพอร์ตทั้งสองต้องตรงกันสำหรับ 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 ที่มา - ดังนั้นจะมีต้นกำเนิดร่วมกันนี้สำหรับทุกเพจของคุณ!

ส่วนที่น่าอึดอัดที่สุดของเทคนิคนี้คือคุณต้องรอให้ iframe โหลดก่อนที่จะดำเนินการต่อ ดังนั้นคุณจึงไม่สามารถเริ่มใช้ localStorage ในตัวจัดการ DOMContentLoaded ของคุณได้ นอกจากนี้คุณอาจต้องการเพิ่มการจัดการข้อผิดพลาดเพื่อตรวจสอบว่า iframe ที่ซ่อนไม่สามารถโหลดได้อย่างถูกต้องหรือไม่

เห็นได้ชัดว่าคุณควรตรวจสอบให้แน่ใจว่า iframe ที่ซ่อนอยู่ไม่ได้ถูกลบออกหรือถูกสำรวจตลอดช่วงอายุการใช้งานของเพจของคุณ ... OTOH ฉันไม่รู้ว่าผลลัพธ์ของมันจะเป็นอย่างไร แต่สิ่งที่ไม่ดีจะเกิดขึ้น

และข้อแม้: การตั้งค่า / การเปลี่ยนแปลงdocument.domainสามารถบล็อกได้โดยใช้Feature-Policyส่วนหัวซึ่งในกรณีนี้เทคนิคนี้จะไม่สามารถใช้งานได้ตามที่อธิบายไว้


อย่างไรก็ตามมีการกำหนดลักษณะทั่วไปที่ซับซ้อนมากขึ้นอย่างมีนัยสำคัญของเทคนิคนี้ซึ่งไม่สามารถบล็อกได้Feature-Policyและยังอนุญาตให้โดเมนที่ไม่เกี่ยวข้องทั้งหมดแชร์ข้อมูลการสื่อสารและคนงานที่ใช้ร่วมกันได้ (เช่นไม่ใช่แค่โดเมนย่อยนอกโดเมนหลักทั่วไป) @ Mayank Jain อธิบายไว้แล้วในคำตอบของพวกเขากล่าวคือ:

แนวคิดทั่วไปก็คือคุณสร้าง iframe ที่ซ่อนอยู่เพื่อระบุต้นทางที่ถูกต้องสำหรับการเข้าถึง แต่แทนที่จะแล้วก็โลภคุณสมบัติหน้าต่าง iframe โดยตรงคุณใช้สคริปต์ภายใน iframe ที่จะทำทั้งหมดของการทำงานและให้คุณติดต่อสื่อสารระหว่าง iframe และหน้าต่างหลักของคุณเป็นเพียงการใช้และpostMessage()addEventListener("message",...)

ใช้งานได้เนื่องจากpostMessage()สามารถใช้งานได้แม้กระทั่งระหว่างหน้าต่างที่มาจากแหล่งอื่น แต่ก็ซับซ้อนกว่าอย่างมากเนื่องจากคุณต้องส่งทุกอย่างผ่านโครงสร้างพื้นฐานการส่งข้อความบางประเภทที่คุณสร้างขึ้นระหว่าง iframe และหน้าต่างหลักแทนที่จะใช้ localStorage, IndexedDB และอื่น ๆ API โดยตรงในโค้ดของหน้าต่างหลักของคุณ


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 คำตอบนี้คือ ไม่ดี.
Don Omondi

เฮ้ @DonOmondi ฉันจะขอบคุณถ้าคุณสามารถช่วยฉันด้วยลิงก์สำหรับสิ่งที่คุณกำลังแนะนำ!
Ayush Baheti

3
OP ขอให้ "ใช้ localStorage ข้ามโดเมนย่อย" คำตอบของคุณคือ "เปลี่ยนเส้นทาง www ไปยังที่ไม่มี www" สิ่งที่แตกต่างกันมาก แต่จะทำงานได้ก็ต่อเมื่อโดเมนย่อยเฉพาะคือ "www.abc.com" สำหรับกรณีทั่วไปคำตอบอื่น ๆ ที่นี่คือ ในทางปฏิบัติมากขึ้น
Don Omondi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.