2014-11-05 43 views
2

我正在研究一個必須支持IE10的角度web應用程序。我需要對我們的企業salesforce服務器進行跨域調用。在chrome中(我們不支持正式的,但我們都在開發)調用失敗,因爲chrome會讓OPTIONS預檢呼叫到不支持CORS的salesforce服務器。Angular.js xhr.open()拋出「訪問被拒絕」錯誤

但是,IE並沒有做出CORS預檢,所以我認爲我打這個電話沒有任何問題。但是我得到了「訪問被拒絕」。從角碼內部深處拋出的錯誤。

進一步深挖發現,在角(v1.2.21)發生故障的具體線路是:

xhr.open(method, url, true); (on line 8544 if you happen to have version 1.2.21). 

在看着githubgoogle groupsstack overflow線程,我看到的問題可能與方式IE想要處理跨域請求,特別是哪個xhr對象被調用來進行調用。

看來,老版本的角度有這個問題,但它是通過將前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)失敗。有誰知道問題是什麼?我很難相信角度無法處理IE中的跨域調用,所以我想我只是錯過了一些東西。

+0

是你混合http和https? – epascarello 2014-11-05 18:32:48

+0

@epascarello是的。我們的地址是'http:// ...',salesforce地址是'https:// ...'但是,如果我將他們的地址更改爲'http',我仍然會遇到同樣的問題。訪問被拒絕,實際上沒有對salesforce進行調用。 – tengen 2014-11-05 19:22:34

+2

而那會是你的問題。 http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx – epascarello 2014-11-05 19:50:57

回答

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); 
     }); 
} 
+0

我可以建議你爲此添加internet-explorer-8和9標籤嗎?以及在標題中包括Internet Explorer和Cors。這些事情會幫助我更快地找到問題。 – tophstar 2015-06-05 17:57:53