如何获得跨源资源共享(CORS)后请求工作

我在本地局域网(machineA)上有一台机器,它有两个web服务器。第一个是XBMC中的内置程序(在端口8080上),它显示我们的库。第二个服务器是一个CherryPy python脚本(端口8081),我用它按需触发文件转换。文件转换由XBMC服务器提供的页面的AJAX POST请求触发。

  • Goto http://machineA:8080显示库
  • 显示Library。
  • 用户单击“转换”链接,发出以下命令-

jQuery Ajax请求

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • 浏览器发出一个带有以下报头的HTTP 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 OK)

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报头(Access-Control-Allow-Origin: *)

为了排除故障,我还发布了相同的$。http://jquery.com中的post命令。这就是我难住的地方,从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 OK)

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

我不明白为什么同样的请求在一个站点上可以工作,而在另一个站点上就不行。我希望有人能指出我错过了什么。谢谢你的帮助!

847169 次浏览

我终于偶然发现了这个“一个CORS POST请求从简单的javascript,但为什么不是用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

要求:

 $.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

结合Laravel解决了我的问题。只需添加这个头到你的jquery请求Access-Control-Request-Headers: x-requested-with,并确保你的服务器端响应有这个头设置Access-Control-Allow-Headers: *

我为这个问题纠结了几个星期。

要做到这一点,最简单、最兼容和最不受黑客攻击的方法可能是使用提供者JavaScript API,它不进行基于浏览器的调用,可以处理跨源请求。

例如Facebook JavaScript API和谷歌JS API。

如果你的API提供者不是当前的,在它的响应中不支持Cross Origin Resource Origin '*'头,并且没有JS API(是的,我是在说你雅虎),你有三个选择之一-

  1. 在你的请求中使用jsonp,它添加了一个回调函数到你的URL,在那里你可以处理你的响应。 注意,这将改变请求URL,所以你的API服务器必须准备好处理URL末尾的?callback=

  2. 将请求发送到您的API服务器,该服务器是您的控制器,与客户端处于同一域中,或者启用了跨源资源共享,您可以将请求代理到第三方API服务器。

  3. 可能在您发出OAuth请求并需要处理用户交互的情况下最有用哈哈!window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')

以下是对我有用的方法的总结:

定义一个新函数(包装$.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);

这是我所知道的从JS真正POST跨域的唯一方法。

JSONP将POST转换为GET,后者可能在服务器日志中显示敏感信息。

现在说这个有点晚了,但我已经为此挣扎了好几天了。这是有可能的,我在这里找到的答案都不奏效。这看似简单。 下面是.ajax调用:

    <!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='steve@XXX.com'",
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>

我花了些时间才找到答案。

如果您的服务器响应正确,并且请求是有问题的,您应该在请求中的withCredentials: true中添加withCredentials: true:

$.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是要求

此函数将从启用cors的页面异步获取HTTP状态应答。如果通过XMLHttpRequest访问,只有具有正确标题的页面才会返回200状态——无论是使用GET还是POST。如果您只需要一个json对象,除了使用JSONP之外,在客户端无法解决这个问题。

可以修改以下内容以获得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>

我解决了自己的问题时使用谷歌距离矩阵API通过设置我的请求头与Jquery ajax。看看下面的内容。

var settings = {
'cache': false,
'dataType': "jsonp",
"async": true,
"crossDomain": true,
"url": "https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=place_id:"+me.originPlaceId+"&destinations=place_id:"+me.destinationPlaceId+"&region=ng&units=metric&key=mykey",
"method": "GET",
"headers": {
"accept": "application/json",
"Access-Control-Allow-Origin":"*"
}
}


$.ajax(settings).done(function (response) {
console.log(response);


});
注意我在设置中添加了什么
* * < / p >
"headers": {
"accept": "application/json",
"Access-Control-Allow-Origin":"*"
}
< br > < p > * *

.

.

我有完全相同的问题,jquery ajax只给了我在post请求的cors问题得到请求工作得很好-我累了上面的一切没有结果。我有正确的头在我的服务器等。改用XMLHTTPRequest而不是jquery立即解决了我的问题。无论我使用哪个版本的jquery,它都没有修复它。如果不需要向后兼容浏览器,Fetch也可以正常工作。

        var xhr = new XMLHttpRequest()
xhr.open('POST', 'https://mywebsite.com', true)
xhr.withCredentials = true
xhr.onreadystatechange = function() {
if (xhr.readyState === 2) {// do something}
}
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(json)

希望这能帮助其他有同样问题的人。

如果由于某些原因,在尝试添加报头或设置控制策略时,你仍然没有得到任何地方,你可以考虑使用apache ProxyPass…

例如,在一个使用SSL的<VirtualHost>中添加以下两个指令:

SSLProxyEngine On
ProxyPass /oauth https://remote.tld/oauth

确保加载了以下apache模块(使用a2enmod加载它们):

  • 代理
  • proxy_connect
  • proxy_http

显然,为了使用apache代理,你必须改变你的AJAX请求url…