Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用子域时防止飞行前选项_Javascript_Ajax_Cors_Preflight - Fatal编程技术网

Javascript 使用子域时防止飞行前选项

Javascript 使用子域时防止飞行前选项,javascript,ajax,cors,preflight,Javascript,Ajax,Cors,Preflight,给定两个子域: web.mysite.com和api.mysite.com 当前从web.向api.发出任何请求都会导致发出飞行前选项请求。如果不在中国额外增加6亿美元的请求,这就不会是什么大问题 我被告知设置document.domain='mysite.com'可以解决这个问题,但这一点都没有帮助 是否可能/如何在发送到不同的子域时禁用选项请求。使用iframe技术解决了这一问题,这似乎是Facebook/Twitter所做的 步骤如下: 1)将document.domain设置为根域。因此

给定两个子域:

web.mysite.com
api.mysite.com

当前从
web.
api.
发出任何请求都会导致发出飞行前选项请求。如果不在中国额外增加6亿美元的请求,这就不会是什么大问题

我被告知设置
document.domain='mysite.com'可以解决这个问题,但这一点都没有帮助


是否可能/如何在发送到不同的子域时禁用选项请求。

使用
iframe
技术解决了这一问题,这似乎是Facebook/Twitter所做的

步骤如下:

1)
document.domain
设置为根域。因此,给定url
http://site.mysite.com/
我在JavaScript中设置域,比如
document.domain='mysite.com'

2)设置从API域提取HTML文件的iframe

将其设置为不可见的位置

3)设置接收方页面的HTML以设置域:

<!DOCTYPE html><body><script>document.domain='mysite.com'</script></body></html>
5)将子窗口分配给变量

window.tempIframeCallback = function() {
  window.childWindow = window.receiver.contentWindow;
}
6)从子窗口而不是主窗口生成
XMLHttpRequest()

var xhr = new window.childWindow.XMLHttpRequest();
现在,所有请求都将在没有飞行前
OPTIONS
request的情况下发送


7)使用jQuery时,还可以在设置中设置xhr的来源:

$.ajax({
  ...
  xhr: function() {
    return new window.childWindow.XMLHttpRequest();
  }
});

作为@Phill答案的补充,这里是最终的html代码,它还公开了iframe的
fetch
函数:

<!DOCTYPE html>
<html><body>
<script>
    document.domain = 'mysite.com';
    window.setupAPI = function() {
        var receiverWindow = window.receiver.contentWindow;
        // you may also want to replace window.fetch here
        window.APIfetch = receiverWindow.fetch;
        // same thing, you may as well replace window.XMLHttpRequest
        window.APIXMLHttpRequest = receiverWindow.XMLHttpRequest;
    }
</script>
<iframe id="receiver" 
        src="http://api.mysite.com/receiver" 
        style="position:absolute;left:-9999px"
        onload="window.setupAPI()"></iframe>
</body></html>

document.domain='mysite.com';
window.setupAPI=函数(){
var receiverWindow=window.receiver.contentWindow;
//您可能还需要在此处替换window.fetch
window.APIfetch=receiverWindow.fetch;
//同样,您也可以替换window.XMLHttpRequest
window.APIXMLHttpRequest=receiverWindow.XMLHttpRequest;
}
当然,HTML“”应该检索:

<!DOCTYPE html>
<html><body><script>
    document.domain='mysite.com';
</script></body></html>

document.domain='mysite.com';

然后,在JS代码中,您现在可以像使用
fetch
APIXMLHttpRequest
一样使用
APIfetch
XMLHttpRequest
。。。等等,无论使用何种方法和内容类型,都不再有飞行前请求

以下是一种全javascript方法:

document.domain = 'mysite.net';
var apiIframe = document.createElement('iframe');
apiIframe.onload = function(){
    window.XMLHttpRequest = this.contentWindow.XMLHttpRequest;
};
apiIframe.setAttribute('src', API_URL + '/iframe');
apiIframe.style.display = 'none';
document.body.appendChild(apiIframe);
其中,API_URL+“/iframe”返回以下内容:

<!DOCTYPE html><body><script>document.domain = 'mysite.net'</script></body></html>
document.domain='mysite.net'

执行JSONP请求可以解决这个问题吗?我现在没有能力尝试,但可能值得研究一下?jsonp会删除预飞行,但是,如果它不支持jsonp,这可能会导致api本身出现问题。用jsonp处理PUT和POST请求有点困难。我们主要是想只为GET解决它。我想知道如果发送一个带有凭据的cookie而不是在标题中,是否会有帮助,那么就不会有自定义的标题。我认为cookie仍然会触发它(但无论如何值得一试)。如果您的api能够支持,那么如果仅获取,jsonp可能是最好的选择。@KevinB我通过创建一个iframe并为两者加载相同的域,然后将窗口从iframe拉回到父对象,并使用它创建XMLHttpRequest对象,从而使它起作用。然后我可以在父级上调用它,所有请求都不再包含选项请求。当我有机会的时候,我会写得更详细。非常感谢你的这个想法!对于未来的读者,这也适用于
fetch
API,使用
window.childWindow.fetch()
而不是
window.fetch()
。疯狂的是,如果没有像这样的黑客解决方案,web标准无法适应这样的情况……目前尝试此解决方案的任何人(2016年12月)都应该意识到,如果API域不是网站本身所在域的子域,那么这将不起作用。例如,如果您的站点位于www.example.org上,则类似于api.example.org的内容将不起作用,并且浏览器将拒绝设置
document.domain
@AdamReis,因为它可以正常工作。如果您不使用apex域,但使用子域(例如app.example.org),然后尝试连接到另一个子域(例如api.example.org),则不允许这样做。Chrome将拒绝您更改
document.domain
。相反,您可以使用api.app.example.org,这是允许的。在我们的应用程序中,我们使用子域来标识租户,因此我们不能简单地使用apex域。@adamreis我认为它从未在子域之间进行过设置。它必须是下面的域。在任何情况下,我现在都使用AWS api网关,只将/api路由到api和s3,不再处理这个问题。我认为由于这个错误(Chrome):“未捕获的DomeException:阻止源代码为“www.example.org”的帧访问跨源代码帧。”我认为这是一个CSP()问题,不是吗?我认为由于这个错误(Chrome):“未捕获的DomeException:阻止了源代码为“www.example.org”的帧访问跨源帧。”我认为这是一个CSP()问题,不是吗?
<!DOCTYPE html><body><script>document.domain = 'mysite.net'</script></body></html>