我正在开发一个必须支持IE10的角度Web应用程序。我需要对我们的企业salesforce服务器进行跨域调用。在chrome(我们不正式支持,但我们都在开发)中,调用失败,因为chrome对salesforce服务器进行OPTIONS预检调用,而该服务器不支持CORS。
然而,IE没有进行CORS预检,所以我认为我可以毫无问题地拨打这个电话。但是我得到了“访问被拒绝”。从角度代码深处抛出的错误。
进一步挖掘揭示出角度(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文件中的代码,就可以为特定的salesforce调用返回该对象:
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)
的行失败。有谁知道问题是什么?我很难相信角度没有办法处理IE中的跨域调用,所以我想我只是缺少一些东西。
答案 0 :(得分: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 stackoverflow 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://stackoverflow.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 stackoverflow 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);
});
}