【问题标题】:cross domain localstorage with javascript使用 javascript 跨域本地存储
【发布时间】:2016-03-01 15:52:21
【问题描述】:

我们有一个托管在域 api.abc.com 上的 javascript api.js。它管理本地存储。

我们在我们的网站 abc.com 和 login.abc.com 中包含了这个 javascript 作为一个跨域 js,比如

<script src="http://api.abc.com/api.js">

我了解 localstoarge 是基于每个域的。但是,由于 api.js 是从 api.abc.com 加载的,我希望它可以从两个域访问 api.abc.com 的本地存储。不幸的是,情况似乎并非如此。当 api.js 将一个域的值存储在 localstoarge 中时,从另一个域加载时它无法访问它。

有什么想法吗?

【问题讨论】:

  • 我不这么认为。 api.js 在浏览器的客户端上执行,带有域。这才是最重要的。
  • 脚本从哪里来没关系(脚本可以从CND加载你不希望localStorage保存在CDN域上),但如果你需要跨域localStorage是一种使用代理iframe的方式,查看这篇文章Cross-Domain LocalStorage。您可以使用 iframe 与不同域上的任何 API 进行交互。

标签: javascript local-storage cross-domain


【解决方案1】:

使用跨域 postmessage 和 iframe 怎么样?

因此,在您的错误域页面上,您包含一个 iframe,该 iframe 将带有 cookie 数据的消息发回。

这是一个跨域邮件的可靠示例: http://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage

实时示例: http://codepen.io/anon/pen/EVBGyz//分叉的发件人代码,有微小的变化:):

window.onload = function() {
    // Get the window displayed in the iframe.
    var receiver = document.getElementById('receiver').contentWindow;

    // Get a reference to the 'Send Message' button.
    var btn = document.getElementById('send');

    // A function to handle sending messages.
    function sendMessage(e) {
        // Prevent any default browser behaviour.
        e.preventDefault();

        // Send a message with the text 'Hello Treehouse!' to the new window.
        receiver.postMessage('cookie data!', 'http://wrong-domain.com');
    }

    // Add an event listener that will execute the sendMessage() function
    // when the send button is clicked.
    btn.addEventListener('click', sendMessage);
}

收货人代码:

window.onload=function(){
    var messageEle=document.getElementById('message');
    function receiveMessage(e){
        if(e.origin!=="http://correct-domain.com")
        return;
        messageEle.innerHTML="Message Received: "+e.data;
    }
    window.addEventListener('message',receiveMessage);
}

【讨论】:

    【解决方案2】:

    正如您在帖子中所注意到的,localStorage(也是 sessionStorage)不会存储在与域 api.abc.com 相关的存储中。如果是这种情况,通过使用 localStorage 的库的 CDN 版本,您将不得不与使用该库的所有其他网站共享存储空间。

    一个好的解决方案是使用带有 postMessage 的 iframe,如以下堆栈溢出中所述: use localStorage across subdomains

    【讨论】:

    • 没错,你的观点是正确的,但是 CDN 通常是不同的域,我希望它在子域之间被允许,就像允许 cookie 一样。
    【解决方案3】:

    您可以试试 Zendesk 的 cross-storage。基本上, 有集线器和客户端:

    • 集线器:驻留在任何服务器上,直接与 LocalStorage API 交互

    • 客户端:使用嵌入式 iframe 加载中心,发布消息,与数据交互

    关键是您可以配置每个主机或域客户端可能拥有的权限(获取、设置、删除)。 该库分为两种类型的组件:集线器和客户端。

    应注意限制双向的来源 沟通。因此,在初始化集线器时,一个数组 权限对象被传递。来自客户端的任何消息,其来源 不匹配的模式被忽略,以及那些不在 允许的方法集。强制执行该组权限谢谢 同源政策。但是,请记住,任何用户都有 完全控制他们的本地存储数据——它仍然是客户端数据。 这只会限制每个域或网络应用级别的访问。

    【讨论】:

      【解决方案4】:

      其他答案都忽略了这样一个事实,即您并没有真正跨域操作,只是在子域之间。

      您仍然需要一个隐藏的 iframe 来封装您要访问的 localStorage 存储的来源(api.abc.com),但是通过在主窗口和隐藏 iframe 上设置document.domain = "abc.com",它们可以直接交互。

      然后你就可以直接使用hiddenIFrame.contentWindow.localStorage 而不是window.localStorage,并且忘记通过 postMessage() 做任何事情的头痛。

      我在这里发布了这个答案的更详细版本:https://stackoverflow.com/a/63602446/999120

      【讨论】:

        【解决方案5】:

        使用 iframe 将数据存储在本地存储和 postMessage API 以在父域和 iframe 之间进行通信

        1. 使用消息事件侦听器创建 iframe 以将数据存储在 iframe 域的本地存储中

          window.addEventListener("message", handleMessage, false);
          
          function handleMessage(e) {
          let {key, value, method} = e.data;
          if (method == 'store') {
              window.localStorage.setItem(key, value); // Store data in iframe domain local storage
          } else if (method == 'retrieve') {
              let response = window.localStorage.getItem(key);
              e.source.postMessage({
                  key,
                  response,
                  method: 'response'
              }, '*'); // Retrieve local storage data
          }
          

          }

        2. 将消息从父域传递到 iframe 以存储数据

          document.getElementById('myFrameId').contentWindow.postMessage({
          key: 'key',
          value: data,
          method: 'store'
          });
          
        3. 从 iframe 中检索数据

           document.getElementById('myFrameId').contentWindow.postMessage({
           method: 'response',
           key: 'key'
           });
          
           window.addEventListener("message", handleResponse, false);
          
           function handleResponse(e) {
            let {key,value,method} = e.data
            if (method == 'response') {
              console.log('Response Key', key);
              console.log('Response value', value)
            }
           }  
          

        【讨论】:

          猜你喜欢
          • 2014-04-29
          • 2022-10-26
          • 1970-01-01
          • 1970-01-01
          • 2016-11-29
          • 2023-04-07
          • 1970-01-01
          • 2019-01-01
          • 1970-01-01
          相关资源
          最近更新 更多