site.example
和www.site.example
存储它们自己单独的localStorage对象。我相信www
被认为是一个子域(如果你问我的话,这是一个愚蠢的决定)。如果用户最初在site.example
上,并决定在下一次访问时输入www.site.example
,那么她所有的个人数据都将无法访问。如何使所有“子域”共享与主域相同的localStorage?site.example
和www.site.example
存储它们自己单独的localStorage对象。我相信www
被认为是一个子域(如果你问我的话,这是一个愚蠢的决定)。如果用户最初在site.example
上,并决定在下一次访问时输入www.site.example
,那么她所有的个人数据都将无法访问。如何使所有“子域”共享与主域相同的localStorage?以下是我跨域使用它的方式...
parent.example
- 使用一个iframechild.example
域中,只需要向您的parent.example
iframe发送postMessage消息parent.example
iframe通信。localStorage
规范需要更加灵活。 - ValeriiVasin我同意其他评论者的看法,这似乎应该是localStorage的可规定选项,因此不需要使用work-arounds。
我建议将site.example
重定向到www.site.example
,以保持一致性并避免出现此类问题。
此外,请考虑使用跨浏览器解决方案,例如PersistJS,它可以使用每个浏览器的本地存储。
Location
头部、通过 <meta>
HTML 标签或甚至是通过 window.location
的 JS。 - Sony Santosif (!/^www/.test(location.hostname)) location.href=location.href.replace('://','://www.')
- oriadam设置主域中的Cookie:
document.cookie = "key=value;domain=.mydomain.example"
然后从任何主域或子域中获取数据,并将其设置在localStorage上。
[2020年11月更新: 此解决方案依赖于能够设置document.domain
。不幸的是,现在已经废弃了这种能力。此外,请注意,这样做会消除域和子域之间的“防火墙”,容易受到XSS攻击或其他恶意脚本的攻击,并且对共享托管具有进一步的安全影响,如MDN页面所述。 2022年9月更新: 从Chrome v109开始,只有在发送Origin-Agent-Cluster: ?0
头的页面上才能设置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.com服务器上的页面,请选择最轻量级的页面并将脚本插入其中。一些“未找到”页面可能会很好)。
(4)隐藏的iframe页面上的脚本只需要(a)设置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>
iframeReady()
)添加到你的unsafeWindow
中。因此,更好的通知主窗口用户脚本的方法是使用自定义事件: window.parent.dispatchEvent(new CustomEvent("iframeReady"));
iframe.contentWindow.localStorage
、iframe.contentWindow.indexedDB
、iframe.contentWindow.BroadcastChannel
、iframe.contentWindow.SharedWorker
而不是window.localStorage
、window.indexedDB
等等...并且所有这些对象都将被限定在所选择的 https://example.com 来源 - 因此它们将为您的所有页面具有相同的共享来源!document.domain
可能会被Feature-Policy
头阻止,在这种情况下,此技术将无法按描述使用。
Feature-Policy
阻止,并且还允许完全不相关的域共享数据、通信和共享工作者(即不仅是共同超域的子域)。@Mayank Jain 在他们的答案中已经描述了这个概念,即:postMessage()
和addEventListener("message",...)
在 iframe 和主窗口之间进行通信。
这是可行的,因为即使在不同来源的窗口之间,也可以使用postMessage()
。但这也更加复杂,因为您必须通过一些消息传递基础设施来传递所有内容,该基础设施是在iframe和主窗口之间创建的,而不能直接在主窗口代码中使用localStorage、IndexedDB等API。
www
和非 www
网站有不同的内容,否则为什么不进行重定向,这也是 OP 提出这个问题的原因。但是,通过这种方法,一个子域名的所有 XSS 漏洞将与另一个子域名共享,从而增加了风险。 - Colm Bhandal这种解决方案会带来很多问题,例如一致性和SEO考虑因素。在主域名上进行重定向是最好的解决方案。
在服务器层面上进行重定向。
如何使用Nginx将www重定向到非www。
或者如果您正在使用Route 53等其他级别,则可以使用
www.site.example
。这样,它将始终使用www.site.example
的本地存储。.htaccess
文件(如果您还没有该文件),并添加以下内容:RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]