IE9使用带有CORS的jQuery AJAX出现“访问被拒绝”错误

123

以下内容在所有浏览器中均有效,除了IE(我正在测试IE 9)。

jQuery.support.cors = true;
...
        $.ajax(
            url + "messages/postMessageReadByPersonEmail",
            {
                crossDomain: true,
                data: {
                    messageId       : messageId,
                    personEmail     : personEmail
                },
                success: function() {
                    alert('marked as read');
                },
                error: function(a,b,c) {
                    alert('failed');
                },
                type: 'post'
            }
        );

我有另一个使用 dataType: 'jsonp' 的函数,但我不需要在这个 AJAX 调用中返回任何数据。我的最后一招将是返回一些包装在 JSONP 中的胡言乱语,只是为了让它正常工作。

有没有想法为什么 IE 会在返回没有数据的 CORS 请求时出错?


由于所有提供的答案都对我无效(我还必须将cookie传递到CORS请求中,但在使用XDomainRequest时这是不允许的),因此这里有一个解决方法:http://blog.gauffin.org/2014/04/how-to-use-cors-requests-in-internet-explorer-9-and-below/。代理拯救了我!:p - wimvds
12个回答

150
这是一个已知的 jQuery bug。jQuery 团队表示“没有计划在核心中支持它,而更适合作为插件。”(参见此评论)。 IE 不使用 XMLHttpRequest,而是使用名为 XDomainRequest 的替代对象。 有一个可用的插件来支持 jQuery,可以在这里找到https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

编辑 函数$.ajaxTransport注册了一个传输工厂。传输工厂被$.ajax 内部使用来执行请求。因此,我假设您应该能够像往常一样调用$.ajax。有关传输工厂和扩展$.ajax的信息可以在这里找到。

另外,这个插件的一个可能更好的版本可以在这里找到。

另外两点注意事项:

  1. 对象XDomainRequest是从IE8开始引入的,在低于该版本的浏览器中将无法使用
  2. 从IE10开始,CORS将使用普通XMLHttpRequest进行支持

编辑2:http到https的问题

请求必须针对与托管页面相同的方案

这个限制意味着,如果你的AJAX页面位于http://example.com,那么你的目标URL也必须以HTTP开头。同样地,如果你的AJAX页面位于https://example.com,那么你的目标URL也必须以HTTPS开头。

来源:http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx 这篇文章主要介绍了IE浏览器中跨域请求的限制、局限性和解决方法。

12
插件的“更好版本”是固有的;我只需将其包含在我的页面中,它就会自动修复我的$.ajax调用 :) 当然,前提是您已经设置了所有必要的标头 - Kato
5
补充dennisg的答案,xdr.js有一个bug:ajaxTransport回调不会被正常调用。我按照https://dev59.com/dWjWa4cB1Zd3GeqPsJYL中的方法进行更改(在ajaxTransport调用的第一个参数前添加“+*”)。 - Volodymyr Otryshko
4
jQuery.XDomainRequest.js 确保当前页面和远程页面都是 http 或 https。这是否意味着您无法从 http 页面调用 https API? - Aaron
2
值得注意的是,Moonscripts Github 存储库中链接的代码是一个不起作用的旧版本。请务必获取最新版本:https://raw.github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest/master/jQuery.XDomainRequest.js - Clintm
3
补充@HariKaramSingh的评论,@Aaron:更改协议(从httphttps)、域名(从google.combing.com)、子域名(从mail.google.commaps.google.com)或端口号(从google.com:80 - 默认端口号到google.com:8080)都将触发“跨域”请求。基本上,在 URL 中第一个斜线之前的所有内容都需要相同。 - allicarn
显示剩余15条评论

62

基于@dennisg的采纳答案,我成功地使用了MoonScript的jQuery.XDomainRequest.js

以下代码在Chrome、Firefox和IE10中正确工作,但在IE9中失败。 我只需包含脚本,它就自动在IE9中工作。 (也可能在8中,但我没有测试。)

var displayTweets = function () {
    $.ajax({
        cache: false,
        type: 'GET',
        crossDomain: true,
        url: Site.config().apiRoot + '/Api/GetTwitterFeed',
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        success: function (data) {
            for (var tweet in data) {
                displayTweet(data[tweet]);
            }
        }
    });
};

3
jQuery.XDomainRequest.js插件正是我所需要的!我无法让iexhr.js插件在HTTP基本身份验证后的请求中工作,但XDomainRequest却像魔法一样奏效了! - James Ford
这对我有用。 我不需要Site.config()。apiRoot +(我假设是为了Twitter ....)但它非常有效,感谢您做到这一点。 - Nicholas Decker
嘿,@JackMarchetti,对于POST请求,它对我不起作用。 - Fernando Vezzali
谢谢@SwampDiner,它很好用,但遗憾的是POST请求被发送为“text/plain”,但对我来说已经解决了问题。 - zanona
1
@cracker 你只有在POST方面遇到问题吗?请再次确认脚本是在jQuery之后加载的,并且你的调用与MoonScript的文档匹配。 - JackMorrissey
显示剩余5条评论

16

1
这个修复很好用——直接放进去就行了。难以置信这个问题存在于jQuery中,但是……谢谢! - Cymen

3
问题在于IE9及以下版本不支持CORS。XDomainRequest仅支持GET/POST和"text/plain"内容类型,如此描述:http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx 因此,如果您想使用所有HTTP动词和/或JSON等,您需要使用另一种解决方案。我编写了一个代理,如果使用IE9或更低版本,则会优雅地降级到代理。如果您正在使用ASP.NET,则无需更改代码。
解决方案分为两部分。第一部分是一个jQuery脚本,它将钩入jQuery ajax处理。如果进行跨域请求并且浏览器是IE,则会自动调用Web服务器:
$.ajaxPrefilter(function (options, originalOptions, jqXhr) {
    if (!window.CorsProxyUrl) {
        window.CorsProxyUrl = '/corsproxy/';
    }
    // only proxy those requests
    // that are marked as crossDomain requests.
    if (!options.crossDomain) {
        return;
    }

    if (getIeVersion() && getIeVersion() < 10) {
        var url = options.url;
        options.beforeSend = function (request) {
            request.setRequestHeader("X-CorsProxy-Url", url);
        };
        options.url = window.CorsProxyUrl;
        options.crossDomain = false;
    }
});

在您的Web服务器中,您需要接收请求,从X-CorsProxy-Url http标头获取值,执行HTTP请求,最后返回结果。
我的博客文章:http://blog.gauffin.org/2014/04/how-to-use-cors-requests-in-internet-explorer-9-and-below/

1

1

我刚刚将所有请求都改成了JSONP,因为这是我们支持的所有浏览器(IE7+和常规浏览器)中唯一的解决方案。请注意,你的答案在技术上适用于IE9,所以你的答案是正确的。


2
对于遇到这个问题的人,需要注意一点——如果你需要支持IE7及以下版本,并且无法控制服务器(例如无法使其支持GET +带有JSONP的脚本标签),那么最好的选择是使用轻量级中间件服务器,将JSONP调用转换为POST并将来自黑盒服务器的响应流式传输回用户。 - mikermcneil

0

0
为了解决这个问题,还要检查一下你的ajax文件中是否包含了一些被引入的.js文件: 在我的ajax.php文件中引入shadowbox.js时,我收到了访问被拒绝的错误。

0

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接