声明
首先,一个免责声明:我在特定的界限内工作,所以虽然看起来我正在寻找一些很长的路要走,但我对自己的能力有限。我知道我应该完全不同地做这件事,但我不能。如果不可能做我想在这里做的事情,那就没关系,我只需要知道。
背景
基本上,这归结为跨域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()完成之前不会执行回调。如果没有办法解决我的初始问题,并且这个选项有承诺,那么我会将此作为一个新问题,但我不想将这个问题与多个主题混为一谈。
答案 0 :(得分:1)
将XMLHttpRequest与CORS一起使用以发出同步跨域请求。
如果服务器不支持cors,请使用添加适当CORS标头的代理,例如: https://cors-anywhere.herokuapp.com/(https://github.com/Rob--W/cors-anywhere的源代码)。
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;
}
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
函数中拆分登录,以便仅在更新该特定值时重新计算该值(而不是在每次更新时重新计算所有内容)。