Angular.js xhr.open() 抛出“拒绝访问”错误
Posted
技术标签:
【中文标题】Angular.js xhr.open() 抛出“拒绝访问”错误【英文标题】:Angular.js xhr.open() throws 'Access is Denied' error 【发布时间】:2015-01-02 01:41:24 【问题描述】:我正在开发一个必须支持 IE10 的 Angular Web 应用程序。我需要对我们的企业 salesforce 服务器进行跨域调用。在 chrome(我们不正式支持,但我们都在其中进行开发)中,该调用失败,因为 chrome 将 OPTIONS 预检调用发送到不支持 CORS 的 salesforce 服务器。
但是,IE 不会进行 CORS 预检,所以我认为进行此调用不会有任何问题。但我收到“拒绝访问”。从 Angular 代码深处抛出的错误。
进一步挖掘显示,失败的 angular (v1.2.21) 中的特定行是:
xhr.open(method, url, true); (on line 8544 if you happen to have version 1.2.21).
在查看github、google groups 和stack overflow 线程时,我发现问题可能出在 IE 想要处理跨域请求的方式上,特别是调用哪个 xhr 对象来进行调用。
似乎旧版本的 Angular 存在此问题,但已通过在 xhr.open()
调用之前添加一个函数来为正在运行的 IE 版本检索正确的 XMLHttpRequest
对象来解决:
var xhr = createXhr(method);
xhr.open(method, url, true);
forEach(headers, function(value, key)
if (isDefined(value))
xhr.setRequestHeader(key, value);
);
所以理论上,正确的 xhr 对象是调用了它的 .open()
方法。但是对我来说,该行会引发“访问被拒绝”错误。
在上面的链接中,似乎通常建议不要使用XMLHttpRequest
对象进行跨域调用,而必须使用XDomainRequest()
。考虑到有角度的人不太可能错过这一点,我还是尝试了,只是手动更改 angular.js 文件中的代码以返回该对象以用于我们特定的销售人员调用:
var xhr;
if (url.indexOf("salesforce.com") > -1)
xhr = new XDomainRequest();
else
xhr = createXhr(method);
xhr.open(method, url, true);
forEach(headers, function(value, key)
if (isDefined(value))
xhr.setRequestHeader(key, value);
);
除了现在代码尝试调用xhr.setRequestHeader(key, value)
的行失败。有谁知道问题是什么?我很难相信 Angular 没有办法处理 IE 中的跨域调用,所以我想我只是遗漏了一些东西。
【问题讨论】:
你在混合http和https吗? @epascarello 是的。我们的地址是http://...
,销售人员地址是https://...
但是,如果我将他们的地址更改为http
,我仍然会遇到同样的问题。访问被拒绝,实际上没有致电 salesforce。
那将是你的问题。 blogs.msdn.com/b/ieinternals/archive/2010/05/13/…
@tengen 看起来像是一个普通的 CORS 问题。如果没有 CORS 支持,您将无法向所述服务器发送 xhr 请求。
@epascarello 该链接很容易成为我见过的对 CORS 的最佳、最易读的解释,而且我也看到了我的公平份额。谢谢! +1!我在文章中看到了一个更新:更新:Internet Explorer 10 现在支持使用 XMLHTTPRequest 的 CORS,这应该比现在已弃用的 XDomainRequest 对象更受欢迎。 这解释了为什么 XDomainRequest 对我来说不是问题在 IE10 中。但即使我对 HTTP 进行 GET 调用(删除那篇文章中 #7 中的问题...混合 http/https 请求)我仍然遇到同样的问题。
【参考方案1】:
虽然您在这里专门说 IE10,但我在 IE8-9 上遇到了同样的问题。我的解决方案是使用跨域对象 window.XDomainRequest。
function loadCaptions()
//Use the XDomainRequest if it is defined (IE8-10), or when angular calls .open on the xhr request will receive "access denied" error.
var url = $scope.captionsUrl;
if (!!window.XDomainRequest)
var xdr = new window.XDomainRequest();
if (xdr)
xdr.open("get", url);
xdr.send();
return;
//You folks on *** can ignore this part, just left in to show how I was requesting the captions leading to "access denied"
$http.get($scope.captionsUrl)
.success(function (captionsJson)
$scope.captionsList = captionsJson;
createCaptionsMap();
)
.error(function (data, status, headers, config)
$cbtErrors.failedToLoadCaptions($scope.captionsUrl);
);
编辑:
这是一个更完整的解决方案,其中包括由于 XDR 请求中的错误和“成功”/“错误”回调导致的内存管理:
function loadCaptions()
//Use the XDomainRequest for IE8-9, or angular get request will recieve "access denied" error.
var url = $scope.captionsUrl;
if (!!window.XDomainRequest)
var xdr = new window.XDomainRequest();
//See explination below why global.pendingXDR is set. Cleaning up that memory here.
var removeXDR = function(xdr)
//You will need a indexOf function defined for IE8. See http://***.com/questions/3629183/why-doesnt-indexof-work-on-an-array-ie8.
var index = global.pendingXDR.indexOf(xdr);
if (index >= 0)
global.pendingXDR.splice(index, 1);
;
if (xdr)
//bind xdr.onload before sending the request (or the event does nothing).
xdr.onload = function()
removeXDR(xdr);
$scope.captionsList = xdr.responseText;
createCaptionsMap();
;
xdr.onerror = function()
removeXDR(xdr);
$cbtErrors.failedToLoadCaptions($scope.captionsUrl);
;
xdr.open("get", url);
xdr.send();
//In Internet Explorer 8/9, the XDomainRequest object is incorrectly subject to garbage collection after
//send() has been called but not yet completed. The symptoms of this bug are the Developer Tools'
//network trace showing "Aborted" for the requests and none of the error, timeout, or success event
//handlers being called.
//To correctly work around this issue, ensure the XDomainRequest is stored in a global variable until
//the request completes.
global.pendingXDR = [];
global.pendingXDR.push(xdr);
return;
//You folks on *** can ignore this part, just left in to show how I was requesting the captions leading to "access denied"
$http.get($scope.captionsUrl)
.success(function (captionsJson)
$scope.captionsList = captionsJson;
createCaptionsMap();
)
.error(function (data, status, headers, config)
$cbtErrors.failedToLoadCaptions($scope.captionsUrl);
);
【讨论】:
我可以建议您在其中添加 internet-explorer-8 和 9 标签吗?以及标题中的 Internet Explorer 和 cors。这些东西会帮助我更快地找到问题。以上是关于Angular.js xhr.open() 抛出“拒绝访问”错误的主要内容,如果未能解决你的问题,请参考以下文章