2014-03-13 78 views
13

我在通過jQuery的$ .ajax函數處理過的第三方API上調用POST。然而,當我打這個電話,我得到了以下錯誤:XMLHttpRequest cannot load http://the-url.com. The request was redirected to 'http://the-url.com/anotherlocation', which is disallowed for cross-origin requests that require preflight.跨域AJAX請求不起作用

我從this post看到,這可能是一個錯誤的Webkit,所以我想它在Firefox(我在Chrome開發),我得到了相同的結果。我在Chrome和Firefox上嘗試了這一點,並獲得了相同的結果。

this post,我也由$就功能crossDomain屬性設置爲true並設置dataTypejsonp使用JSONP都試過。但是,這導致500內部服務器錯誤。

當我用--disable-web-security標誌啓動Chrome時,我沒有任何問題。但是,如果我正常啓動瀏覽器,那麼我得到錯誤。

所以,我想這可能是一個2部分的問題。我能做些什麼來完成這個跨域請求?如果JSONP是答案,那麼我該如何確定第三方API是否正確設置以支持這一點?

編輯:下面是截圖的時候我就與瀏覽器安全呼叫禁止:https://drive.google.com/file/d/0Bzo7loNBQcmjUjk5YWNWLXM2SVE/edit?usp=sharing

這裏的screenchost時,我就與啓用(正常人一樣)的瀏覽器安全呼叫:https://drive.google.com/file/d/0Bzo7loNBQcmjam5NQ3BKWUluRE0/edit?usp=sharing

回答

3

,我想出了是使用捲曲(如@waki提及)的解決方案,但支持SOAP略加修改。然後,我不調用第三方API(配置不正確)的AJAX調用,而是調用我的本地PHP文件,然後對第三方API進行SOAP調用,並將數據傳回我的PHP文件,我可以然後處理它。這讓我忘記了CORS以及與之相關的所有複雜性。這裏的代碼(從this問題進行了修改,但沒有進行驗證)。

$post_data = "Some xml here"; 
$soapUrl = "http://yoursite.com/soap.asmx"; // asmx URL of WSDL 


$headers = array(
    "Content-type: text/xml;charset=\"utf-8\"", 
    "Accept: text/xml", 
    "Cache-Control: no-cache", 
    "Pragma: no-cache", 
    "SOAPAction: http://yoursite.com/SOAPAction", 
    "Content-length: " . strlen($post_data), 
); //SOAPAction: your op URL 

$url = $soapUrl; 

// PHP cURL 
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, $url); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
curl_setopt($ch, CURLOPT_POST, true); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); // the SOAP request 
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 

$response = curl_exec($ch); 

/* Check for an error when processing the request. */ 
if(curl_errno($ch) != 0) { 
    // TODO handle the error 
} 

curl_close($ch); 

// TODO Parse and process the $response variable (returned as XML) 
+0

這會工作,但我會稱之爲「解決方法」而不是解決方案。有些人在某些情況下只能依靠前端,而沒有選擇使用後端代理。 – Yann

+0

是的,我希望有更好的解決方案。但是,由於受到安全限制而無法控制服務器,所以通過我控制的服務器進行代理是我遇到的最佳解決方案。 – Don

20

對你的第一個問題,

What can I do to make this cross-domain request?

下面的請求頭首先發送到服務器。基於響應頭,UserAgent(即瀏覽器)將丟棄響應(如果有),並且在頭不加起來時不會將其返回給XHR回調。

Origin: http://yourdomain.com Access-Control-Request-Method: POST Access-Control-Request-Headers: X-Custom-Header

您的服務器,然後應與下列頭回應:

Access-Control-Allow-Origin: http://yourdomain.com Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: X-Custom-Header

例子取自 - https://stackoverflow.com/a/8689332/1304559

您可以使用工具,如提琴手或Web督察網絡選項卡(鉻)或Firebug的網絡選項卡來查找服務器響應您的請求而發回的標頭。

第三方API服務器網址應迴應支持的值。如果它不是你的問題。

不能有很大幫助的JSONP 500服務器錯誤,因爲它說內部服務器錯誤


UPDATE

我看到了你的屏幕截圖,幾件事情要注意這裏

  1. HTTP POST被使用
  2. Access-Control在兩種模式響應中都找到標題。隨着第二狀態碼302
  3. Origin請求頭是null,所以我相信在HTML文件從文件系統,而不是從網站

啓用JSONP

來到開爲什麼JSONP不工作的原因,原因 - (指定ASMX的)Web服務配置未啓用請求的GET模式。 JSONP不適用於POST

爲什麼200的安全保護功能被禁用?

POST請求被直接調用,沒有OPTIONS或在它之前觸發預檢請求,所以服務器只是迴應。

爲什麼302狀態碼啓用了安全性?

首先稍微介紹一下安全標誌未禁用時的情況(默認)。 OPTIONS請求被激發到URL。 URL應以HTTP方法的列表,可以使用,即GETPOST等。本OPTIONS請求的狀態碼應該是200發回響應。

在當前情況下,在執行此操作時會調用一個重定向。重定向指向HTTP服務器錯誤的自定義錯誤處理程序。我相信這是404錯誤,這是被抓,並被重定向。[這可能是因爲自定義處理程序設置爲ResponseRedirect而不是ResponseRewrite]的原因404是跨域訪問未啓用。

萬一自定義錯誤處理被關閉,這將返回HTTP 500代碼。我相信問題可以通過在發出跨域請求後立即檢查服務器日誌來找到。如果有的話,檢查服務器日誌是否有其他錯誤是很好的。

可能的解決方法

要允許訪問,有兩種方式 - detailed here。或直接將訪問控制標題添加到web.config文件的customheaders部分。

啓用跨域訪問,服務器應該回響應選項,並允許請求通過。除非有其他錯誤,否則應該返回HTTP 200。但是Ajax回調將無法訪問響應。只有當Access-Control-Allow-Origin設置爲「*」或Origin請求標頭值,並且Access-Control根據需要時,才能完成此操作。並且ajax回調將按預期收到響應。

第三點,空Origin。如果Origin請求標頭值被髮回爲Access-Control-Allow-Origin,這將會出現問題。但我假設你將把你的HTML頁面移動到一個Web服務器上,所以這應該不成問題。

希望這會有所幫助!

+1

謝謝。這很有幫助。我查看了Web Inspector網絡選項卡中的網絡調用,但沒有在那裏看到必要的「訪問控制」標頭。我在想這可能是問題所在。如果標題在那裏,它們會顯示在Web Inspector的「網絡」選項卡上,對嗎? – Don

+2

是的,這是正確的。您可以在網絡標籤上試用以從HTML網頁中的CDN下載腳本,例如:http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js 同樣,第三方API應根據需要啓用Access-Control標頭。 – aravind

+0

好的。我看到你在談論什麼,我正在考慮聯繫API的提供者,看看他們爲什麼不支持JSONP。我將網絡選項卡的屏幕截圖附加到問題中。請你看看,讓我知道你的想法? – Don

1

您可以使用cURL? 使用Ajax將數據發送到您的處理程序(在您的服務器上,讓我們稱之爲callback.php)。 在您的文件(callback.php)使用捲曲你的數據:

$post_data = array( 
    'key' => 'key', 
    'test' => 'text' 
    ); 

$curl = curl_init(); 
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); 
curl_setopt($curl, CURLOPT_POST, TRUE); 
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data); 
curl_setopt($curl, CURLOPT_URL, 'http://www.domain.com/'); 
$return = json_decode(trim(curl_exec($curl)), TRUE); 
curl_close($curl); 
在$返回變量

你得到你的數據。

+1

很好的建議,謝謝!我實際上使用了一個稍微修改過的支持SOAP的版本。 – Don

+0

@Don你介意分享SOAP代碼嗎? – BigDong