3

免责声明
首先,免责声明:我在特定的范围内工作,所以虽然看起来我要做的事情很长,但我能做的事情是有限的。我知道我应该以完全不同的方式做这件事,但我不能。如果不可能做我在这里想做的事情,那很好,我只需要知道。


背景
基本上,这归结为一个跨域的 javascript 调用。但是,我需要在返回方法之前等待响应。

假设我有一个页面 - example1.com/host.html。这包含一个 'ProvideValue()' 的 javascript 方法,它返回一个 int。 编辑:此方法必须在找到它的地方执行,因为它可能需要访问该域内的其他资源,并访问为当前会话设置的全局变量。

https://example1.com/host.html

function ProvideValue(){
 return 8;  // In reality, this will be a process that returns a value
}

这个 host.html 页面包含一个指向 example2.com/content.html 的 iframe(注意不同的域)。此 content.html 页面包含一个需要在警报中显示 host.html 值的方法。

https://example2.com/content.html

function DisplayValue(){
 var hostValue = //[get value from ProvideValue() in host.html]
 alert(hostValue);
}

而已。

限制
我可以在 host.html 上运行任何我喜欢的 javascript,但不能在服务器端运行。在 content.html 上,我可以运行 javascript 和任何服务器端。我无法控制 example1.com 域,但可以完全控制 example2.com。

问题
如何在 example2.com/content.html 上的 DisplayValue() 方法中从 example1.com/host.html 上的 ProvideValue() 检索值?


以前的尝试
现在,我尝试了许多跨域技术,但所有(我发现的)它们都使用异步回调。这在这种情况下不起作用,因为我需要向 host.html 发出请求,并接收返回的值,所有这些都在 content.html 上的单个方法的范围内。

我工作的唯一解决方案是依赖异步跨域脚本(使用easyXDM)和example2.com 中的服务器端请求/响应列表。DisplayValue() 方法向 host.html 发出请求,然后立即向服务器同步发布。然后,服务器将等待,直到收到来自跨域回调的响应的通知。在等待期间,回调将再次调用服务器以存储响应。它在 FireFox 和 IE 中运行良好,但 Chrome 在 DisplayValue() 完成之前不会执行回调。如果没有办法解决我最初的问题,并且这个选项有希望,那么我将把它作为一个新问题提出,但我不想用多个主题来混淆这个问题。

4

1 回答 1

1

使用带有CORS的 XMLHttpRequest 进行同步跨域请求。

如果服务器不支持 cors,请使用添加适当 CORS 标头的代理,例如https://cors-anywhere.herokuapp.com/(源代码位于https://github.com/Rob--W/cors - 任何地方)。

示例 1:将同步 XHR 与 CORS 结合使用

function getProvidedValue() {
    var url = 'http://example.com/';

    var xhr = new XMLHttpRequest();
    // third param = false  = synchronous request
    xhr.open('GET', 'https://cors-anywhere.herokuapp.com/' + url, false);
    xhr.send();
    var result = xhr.responseText;
    // do something with response (text manipulation, *whatever*)
    return result;
}

示例 2:使用postMessage

如果使用会话数据动态计算值很重要,请使用postMessage不断更新状态:

顶级文档(host.html):

<script src="host.js"></script>
<iframe name="content" src="https://other.example.com/content.html"></iframe>

host.js

(function() {
    var cache = {
        providedValue: null,
        otherValue: ''
    };
    function sendUpdate() {
        if (frames.content) { // "content" is the name of the iframe
            frames.content.postMessage(cache, 'https://other.example.com');
        }
    }
    function recalc() {
        // Update values
        cache.providedValue = provideValue();
        cache.otherValue = getOtherValue();

        // Send (updated) values to frame
        sendUpdate();
    }

    // Listen for changes using events, pollers, WHATEVER
    yourAPI.on('change', recalc);

    window.addEventListener('message', function(event) {
        if (event.origin !== 'https://other.example.com') return;
        if (event.data === 'requestUpdate') sendUpdate();
    });
})();

中的脚本content.html:content.js

var data = {}; // Global
var parentOrigin = 'https://host.example.com';
window.addEventListener('message', function(event) {
    if (event.origin !== parentOrigin) return;
    data = event.data;
});
parent.postMessage('requestUpdate', parentOrigin);

// To get the value:
function displayValue() {
    var hostName = data.providedValue;
}

这个片段只是这个概念的一个演示。如果要应用该方法,您可能希望在recalc函数中拆分登录,以便仅在更新该特定值时重新计算该值(而不是在每次更新时重新计算所有内容)。

于 2013-08-06T10:04:06.320 回答