同步跨域javascript调用,等待响应 - 是否可能?

时间:2013-08-06 09:52:40

标签: javascript cross-domain

声明
首先,一个免责声明:我在特定的界限内工作,所以虽然看起来我正在寻找一些很长的路要走,但我对自己的能力有限。我知道我应该完全不同地做这件事,但我不能。如果不可能做我想在这里做的事情,那就没关系,我只需要知道。


背景
基本上,这归结为跨域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()完成之前不会执行回调。如果没有办法解决我的初始问题,并且这个选项有承诺,那么我会将此作为一个新问题,但我不想将这个问题与多个主题混为一谈。

1 个答案:

答案 0 :(得分:1)

将XMLHttpRequest与CORS一起使用以发出同步跨域请求。

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

示例1:使用带CORS的同步XHR

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函数中拆分登录,以便仅在更新该特定值时重新计算该值(而不是在每次更新时重新计算所有内容)。