即使正确设置了 document.domain,跨子域 ajax 请求也会被拒绝

Posted

技术标签:

【中文标题】即使正确设置了 document.domain,跨子域 ajax 请求也会被拒绝【英文标题】:Cross-subdomain ajax request denied even when document.domain is set correctly 【发布时间】:2011-12-05 20:42:58 【问题描述】:

在我的应用程序中,我在一个子域 (dev.u413.com) 上有一个网站,我使用 jQuery 向另一个子域 (api.u413.com) 上的 JSON api 发出 ajax 请求。当我在 Chrome 开发工具和 Firefox Firebug 中检查请求时,Access-Control-Allowed-Origin 似乎阻止了我的请求。我将document.domain设置为当前域的后缀:document.domain = 'u413.com';

这是我的要求:

    $.ajax(
        dataType: 'json',
        data:  parseAshtml: true, cli: 'help' ,
        url: 'http://api.u413.com/',
        success: function (response) 
            alert(response.Command);
        
    );

如果我将ajax请求修改为在同一个域上,则请求成功。

    $.ajax(
        dataType: 'json',
        crossDomain: false,
        data:  parseAsHtml: true, cli: 'help' ,
        url: 'http://dev.u413.com/',
        success: function (response) 
            alert(response.Command);
        
    );

为什么会这样?浏览器不应该抱怨跨域问题,因为我根据same origin policy 上的指南将document.domain 设置为两个子域的共同后缀。

我的应用程序目前使用 jsonp,但我觉得正确的 ajax 请求应该按照我上面链接的相同源策略工作。如果不需要,我宁愿不使用 jsonp。难道不能跨子域发出常规的ajax请求吗?

【问题讨论】:

我不想要 jsonp,这就是我的观点。我想跨子域做一个适当的 AJAX 请求,这应该是根据same origin policy 允许的。 @ALex 我已经阅读了该文件,现在我正在考虑其他方式:) @DarinDimitrov 我将如何在 api 域上设置它?它只是一个返回 JSON 数据的 api。 (例如api.u413.com/?cli=help) @AlexFord,没关系我犯了一个错误并删除了我的评论。当您执行 AJAX 时,document.domain 与您的方案无关。看我的回答。 【参考方案1】:

document.domain 不适用于 AJAX。它适用于跨域 iframe 和窗口通信。在您的情况下,您违反了相同的来源策略(表的last line),因此您需要使用 JSONP 或服务器端桥接器。

这是一个非常nice guide,它说明了实现跨域 AJAX 请求的不同技术。

【讨论】:

啊,好的。谢谢您的帮助。我已经让它与 JSONP 一起工作,这很好。当我认为它应该以这种方式工作时,我无法让它工作,我只是感到沮丧。再次感谢。 “好指南”说网站被黑了:( 那么如果我使用 iframe 并使用 javascript 获取 iframe 的内容,它应该可以工作吗? 叹息...你的好指南是“被 Ben AttaCkEr 破解”。 为什么每个人都表现得像 JSONP 解决了任何事情。好的,继续,尝试使用 JSONP 进行 CORS POST,看看能走多远。【参考方案2】:

同源策略是我不得不处理的与浏览器相关的最令人沮丧的话题之一。对我来说愚蠢的是,同一域上的 2 台服务器无法通信。不幸的是,同源策略甚至认为对同一服务器但在不同端口上的 2 个请求违反了同源策略。我认为未来的浏览器会变得更好:

http://www.html5rocks.com/en/tutorials/file/xhr2/

搜索:跨域资源共享 (CORS)

基本上你的服务器只需要设置一个响应头说“是的,允许跨域或跨子域调用服务器 xyz 是可以的”。

我敢肯定,所有浏览器都支持这一点还需要一段时间(而且我必须支持 ie8,直到我们的大多数用户无论如何都关闭它)——但至少隧道尽头有光明。

【讨论】:

【参考方案3】:

您还需要将document.domain = 'u413.com 添加到您的其他子域。

【讨论】:

在哪里添加?它是一个只返回 JSON 的 api。 @Alex,那么 JSONP 是要走的路。 document.domain 只允许两个文档协作。 也许不会,但在 CORS 之前没有太多选择。【参考方案4】:

难道不能跨子域发出常规的ajax请求吗?

这在技术上不是 AJAX,但您可以模仿 AJAX 请求,使表单提交成功跨域。缺点是您无法访问响应,这将导致页面被重定向到表单的ACTION URL。

而不是这个:

jQuery.post('https://www.com',
    'offerCode':523153,
    'accountNumber':'',
    '_item.x':'42',
    '_item.y':'21'
);

使用这个:

jQuery('<form action="https://www.com" method="POST">
      <input type="text" name="offerCode" value="523153">
      <input type="text" name="accountNumber" value="">
      <input type="text" name="_item.x" value="42">
      <input type="text" name="_item.y" value="21">
    </form>').trigger('submit');

【讨论】:

以上是关于即使正确设置了 document.domain,跨子域 ajax 请求也会被拒绝的主要内容,如果未能解决你的问题,请参考以下文章

IE9:设置 document.domain 时访问被拒绝

通过document.domain实现跨域访问

关于跨域的N种方法实践之iframe+domain

document.domain

JS跨域调用之document.domain--相同基础域名页面之间的调用

java web开发跨域问题