2011-04-21 163 views
159

我有一臺機器在我的本地局域網(machineA)上有兩臺Web服務器。第一個是XBMC內置的(在端口8080上)並顯示我們的庫。第二個服務器是一個CherryPy python腳本(端口8081),我用它來根據需要觸發文件轉換。文件轉換由來自XBMC服務器提供頁面的AJAX POST請求觸發。如何獲得跨源資源共享(CORS)後請求工作

  • 轉到http://machineA:8080它顯示庫
  • 庫顯示
  • 用戶點擊 '轉換' 鏈接,發出以下命令 -

jQuery的Ajax請求

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)}) 
  • 瀏覽器發出HT帶有以下標題的TP OPTIONS請求;

請求報頭 - OPTIONS

Host: machineA:8081 
User-Agent: ... Firefox/4.01 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-us,en;q=0.5 
Accept-Encoding: gzip,deflate 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 
Keep-Alive: 115 
Connection: keep-alive 
Origin: http://machineA:8080 
Access-Control-Request-Method: POST 
Access-Control-Request-Headers: x-requested-with 
  • 服務器出現以下響應;

響應頭 - OPTIONS(STATUS = 200行)

Content-Length: 0 
Access-Control-Allow-Headers: * 
Access-Control-Max-Age: 1728000 
Server: CherryPy/3.2.0 
Date: Thu, 21 Apr 2011 22:40:29 GMT 
Access-Control-Allow-Origin: * 
Access-Control-Allow-Methods: POST, GET, OPTIONS 
Content-Type: text/html;charset=ISO-8859-1 
  • 談話然後停止。 (?)的瀏覽器,在理論上,發出POST請求的服務器用正確的迴應CORS標頭(訪問控制允許來源:*)

爲了排除故障,我也發表了同樣的$ .post命令從http://jquery.com。這是我被困在jquery.com,post請求工作的地方,OPTIONS請求在POST之後發送。此交易的標題如下所示;

請求報頭 - OPTIONS

Host: machineA:8081 
User-Agent: ... Firefox/4.01 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-us,en;q=0.5 
Accept-Encoding: gzip,deflate 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 
Keep-Alive: 115 
Connection: keep-alive 
Origin: http://jquery.com 
Access-Control-Request-Method: POST 

響應頭 - OPTIONS(STATUS = 200行)

Content-Length: 0 
Access-Control-Allow-Headers: * 
Access-Control-Max-Age: 1728000 
Server: CherryPy/3.2.0 
Date: Thu, 21 Apr 2011 22:37:59 GMT 
Access-Control-Allow-Origin: * 
Access-Control-Allow-Methods: POST, GET, OPTIONS 
Content-Type: text/html;charset=ISO-8859-1 

請求報頭 - POST

Host: machineA:8081 
User-Agent: ... Firefox/4.01 
Accept: */* 
Accept-Language: en-us,en;q=0.5 
Accept-Encoding: gzip,deflate 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 
Keep-Alive: 115 
Connection: keep-alive 
Content-Type: application/x-www-form-urlencoded; charset=UTF-8 
Referer: http://jquery.com/ 
Content-Length: 12 
Origin: http://jquery.com 
Pragma: no-cache 
Cache-Control: no-cache 

響應頭 - POST(STATUS = 200 OK)

Content-Length: 32 
Access-Control-Allow-Headers: * 
Access-Control-Max-Age: 1728000 
Server: CherryPy/3.2.0 
Date: Thu, 21 Apr 2011 22:37:59 GMT 
Access-Control-Allow-Origin: * 
Access-Control-Allow-Methods: POST, GET, OPTIONS 
Content-Type: application/json 

我想不通,爲什麼同樣的要求會從一個站點工作,而不是其他。我希望有人能夠指出我缺少的東西。謝謝你的幫助!

+0

是CORS需要如果兩個Web服務器在同一臺機器上? – jdigital 2011-04-21 23:48:09

+6

據我所知,這是一個CORS請求,因爲不同的端口。另外,OPTIONS請求表明瀏覽器正在將它視爲CORS請求 – James 2011-04-22 03:02:50

+0

[CORS POST請求可能來自普通javascript,但爲什麼不使用jQuery?](https://stackoverflow.com/questions/5584923/) a-cors-post-request-works-from-plain-javascript-but-why-not-with-jquery) – Liam 2018-02-27 16:30:27

回答

126

我終於偶然發現了這個鏈接 「A CORS POST request works from plain javascript, but why not with jQuery?」 即指出,jQuery的1.5.1添加

Access-Control-Request-Headers: x-requested-with 

頭所有CORS請求。 jQuery 1.5.2不會這樣做。此外,根據同一問題,設置服務器響應標頭爲

Access-Control-Allow-Headers: * 

不允許響應繼續。您需要確保響應頭特別包含所需的頭文件。即:

Access-Control-Allow-Headers: x-requested-with 
48

請求:

$.ajax({ 
      url: "http://localhost:8079/students/add/", 
      type: "POST", 
      crossDomain: true, 
      data: JSON.stringify(somejson), 
      dataType: "json", 
      success: function (response) { 
       var resp = JSON.parse(response) 
       alert(resp.status); 
      }, 
      error: function (xhr, status) { 
       alert("error"); 
      } 
     }); 

迴應:

response = HttpResponse(json.dumps('{"status" : "success"}')) 
response.__setitem__("Content-type", "application/json") 
response.__setitem__("Access-Control-Allow-Origin", "*") 

return response 
+3

如果服務器不接受交叉原點,crossdomain = true不必解決問題。使用dataType:「jsonp」並設置回調如jsonpCallback:「response」將是更好的主意。另請參閱:http://api.jquery.com/jquery.ajax/ – BonifatiusK 2014-11-13 12:17:42

+18

jsonp不適用於POST請求 – 2015-05-20 10:16:16

3

與Laravel結合使用這個解決我的問題。只需將此標題添加到您的jQuery請求Access-Control-Request-Headers: x-requested-with並確保您的服務器端響應具有此標頭集Access-Control-Allow-Headers: *

+3

沒有理由手動將CORS頭添加到請求中。瀏覽器將始終將CORS標題添加到您的請求中。 – 2014-04-13 12:50:02

+0

真正的挑戰是讓服務器用正確的'Access-Control-Allow-Headers'和JQ提供正確的'Access-Control-Request-Headers'(加上任何你通過代碼添加的內容)回覆,這兩者都不能是通配符。它只需要一個「壞」頭來炸開飛行前,例如,使用'If-None-Match'作爲條件GET,如果服務器沒有列出。 – 2017-06-08 17:36:02

8

嗯,我這個問題掙扎了幾個星期。

的最簡單,最符合和不哈克的方式做到這一點是可能使用一個供應商的JavaScript API不使基於瀏覽器的調用,並能處理跨源請求。

例如Facebook JavaScript API和Google JS API。

如果您的API提供程序不是最新的,並且在其響應中不支持跨源資源源'*'標題,並且沒有JS api(是的,我正在談論關於您的雅虎),則會觸發其中一個三個選項 -

  1. 在您的請求中使用jsonp,它向您的URL添加回調函數,您可以在其中處理響應。 買者這將改變請求URL所以你的API服務器必須具備處理?回調=在URL的結尾。

  2. 將請求發送到您的API控制器的API服務器,它與客戶端位於同一個域中,或者啓用了跨域資源共享,您可以將請求代理到第三方API服務器。

  3. 可能是最有用的,你正在OAuth的要求和需要處理的用戶交互的情況哈哈!window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')

1

這是對我工作的總結:

定義一個新的功能(包裹$.ajax簡化):

jQuery.postCORS = function(url, data, func) { if(func == undefined) func = function(){}; return $.ajax({ type: 'POST', url: url, data: data, dataType: 'json', contentType: 'application/x-www-form-urlencoded', xhrFields: { withCredentials: true }, success: function(res) { func(res) }, error: function() { func({}) }}); } 

用法:

$.postCORS("https://example.com/service.json",{ x : 1 },function(obj){ 
     if(obj.ok) { 
      ... 
     } 
}); 

而且與.done,.fail等合作:

$.postCORS("https://example.com/service.json",{ x : 1 }).done(function(obj){ 
     if(obj.ok) { 
      ... 
     } 
}).fail(function(){ 
    alert("Error!"); 
}); 

服務器端(在這種情況下,其中example.com託管),設置這些報頭(加入PHP一些示例代碼):

header('Access-Control-Allow-Origin: https://not-example.com'); 
header('Access-Control-Allow-Credentials: true'); 
header('Access-Control-Max-Age: 604800'); 
header("Content-type: application/json"); 
$array = array("ok" => $_POST["x"]); 
echo json_encode($array); 

這是我所知道的真正POST的唯一途徑來自JS的跨域。

JSONP將POST轉換爲GET,這可能會在服務器日誌中顯示敏感信息。

-4

這對派對來說有點遲,但我一直在爲此奮鬥了幾天。這是可能的,我在這裏找到的答案都沒有奏效。這看似簡單。 這裏的阿賈克斯電話:

<!DOCTYPE HTML> 
 
    <html> 
 
    <head> 
 
    <body> 
 
    <title>Javascript Test</title> 
 
    <script src="http://code.jquery.com/jquery-latest.min.js"></script> 
 
    <script type="text/javascript"> 
 
    $(document).domain = 'XXX.com'; 
 
    $(document).ready(function() { 
 
    $.ajax({ 
 
     xhrFields: {cors: false}, 
 
     type: "GET", 
 
     url: "http://XXXX.com/test.php?email='[email protected]'", 
 
     success: function (data) { 
 
      alert(data); 
 
     }, 
 
     error: function (x, y, z) { 
 
      alert(x.responseText + " :EEE: " + x.status); 
 
     } 
 
    }); 
 
    }); 
 
    </script> 
 
    </body> 
 
    </html>

下面是在服務器端的PHP:

<html> 
 
    <head> 
 
    <title>PHP Test</title> 
 
    </head> 
 
    <body> 
 
     <?php 
 
     header('Origin: xxx.com'); 
 
     header('Access-Control-Allow-Origin:*'); 
 
     $servername = "sqlxxx"; 
 
     $username = "xxxx"; 
 
     $password = "sss"; 
 
     $conn = new mysqli($servername, $username, $password); 
 
     if ($conn->connect_error) { 
 
     die("Connection failed: " . $conn->connect_error); 
 
     } 
 
     $sql = "SELECT email, status, userdata FROM msi.usersLive"; 
 
     $result = $conn->query($sql); 
 
     if ($result->num_rows > 0) { 
 
     while($row = $result->fetch_assoc()) { 
 
     echo $row["email"] . ":" . $row["status"] . ":" . $row["userdata"] . "<br>"; 
 
     } 
 
    } else { 
 
     echo "{ }"; 
 
    } 
 
    $conn->close(); 
 
    ?> 
 
    </body>

+1

值得一提的是,Origin頭部是一個請求頭部,而不是一個響應頭部。你的PHP腳本不應該設置它。 – Noodles 2016-11-24 22:36:23

+0

哼。當我看到你在你的代碼中創建了一個AJAX「GET」時,這讓我很有希望,然後破滅了他們,當時OP很清楚地表示他試圖避免使用「GET」並想使用「POST」。 – 2017-03-26 05:22:38

+0

無論涉及什麼動詞,CORS標頭的工作方式都是相同的。我們可以通過'$ .ajax()'針對正確配置的服務器調用所有動詞。最難的部分是正確獲取'Access-Control-Request-Headers',但即使這樣也不困難。正如前面的海報所指出的,這不能是通配符,而是頭文件的白名單。 – 2017-06-08 17:30:00

6

我花了一些時間來找到解決方案。

如果您的服務器響應正確和要求的問題,您應該在請求中添加withCredentials: truexhrFields

$.ajax({ 
    url: url, 
    type: method, 
    // This is the important part 
    xhrFields: { 
     withCredentials: true 
    }, 
    // This is the important part 
    data: data, 
    success: function (response) { 
     // handle the response 
    }, 
    error: function (xhr, status) { 
     // handle errors 
    } 
}); 

注:jQuery的> = 1.5.1要求

+0

仍然不工作對我:( – 2017-09-18 10:50:23

+0

jquery版本好嗎?你設置'withCredentials:true'?你確定你有相關的頭? – Dekel 2017-09-18 12:30:54

+0

是的,1withCredential:true','jquery version:3.2.1'。其實它是通過郵遞員工作,但它不通過瀏覽器 – 2017-09-18 13:49:01

0

出於某種原因,有關GET請求的問題已與此合併,因此我會在此對其進行回覆。

這個簡單的函數將異步從啓用CORS的頁面獲取HTTP狀態回覆。如果你運行它,你會發現如果通過XMLHttpRequest進行訪問,只有具有適當頭文件的頁面返回200狀態 - 無論是使用GET還是POST。除了可能使用JSONP,如果你只需要一個json對象,在客戶端沒有什麼可以解決這個問題。

下可以很容易地修改,以獲得在xmlHttpRequestObject對象保存的數據:

function checkCorsSource(source) { 
 
    var xmlHttpRequestObject; 
 
    if (window.XMLHttpRequest) { 
 
    xmlHttpRequestObject = new XMLHttpRequest(); 
 
    if (xmlHttpRequestObject != null) { 
 
     var sUrl = ""; 
 
     if (source == "google") { 
 
     var sUrl = "https://www.google.com"; 
 
     } else { 
 
     var sUrl = "https://httpbin.org/get"; 
 
     } 
 
     document.getElementById("txt1").innerHTML = "Request Sent..."; 
 
     xmlHttpRequestObject.open("GET", sUrl, true); 
 
     xmlHttpRequestObject.onreadystatechange = function() { 
 
     if (xmlHttpRequestObject.readyState == 4 && xmlHttpRequestObject.status == 200) { 
 
      document.getElementById("txt1").innerHTML = "200 Response received!"; 
 
     } else { 
 
      document.getElementById("txt1").innerHTML = "200 Response failed!"; 
 
     } 
 
     } 
 
     xmlHttpRequestObject.send(); 
 
    } else { 
 
     window.alert("Error creating XmlHttpRequest object. Client is not CORS enabled"); 
 
    } 
 
    } 
 
}
<html> 
 
<head> 
 
    <title>Check if page is cors</title> 
 
</head> 
 
<body> 
 
    <p>A CORS-enabled source has one of the following HTTP headers:</p> 
 
    <ul> 
 
    <li>Access-Control-Allow-Headers: *</li> 
 
    <li>Access-Control-Allow-Headers: x-requested-with</li> 
 
    </ul> 
 
    <p>Click a button to see if the page allows CORS</p> 
 
    <form name="form1" action="" method="get"> 
 
    <input type="button" name="btn1" value="Check Google Page" onClick="checkCorsSource('google')"> 
 
    <input type="button" name="btn1" value="Check Cors Page" onClick="checkCorsSource('cors')"> 
 
    </form> 
 
    <p id="txt1" /> 
 
</body> 
 
</html>