如何获得跨源资源共享(CORS)后请求工作
我有一台机器在我的本地局域网(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
我想不通,为什么同样的要求会从一个站点工作,而不是其他。我希望有人能够指出我缺少的东西。谢谢你的帮助!
我终于偶然发现了这个链接 “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
请求:
$.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
如果服务器不接受交叉原点,crossdomain = true不必解决问题。使用dataType:“jsonp”并设置回调如jsonpCallback:“response”将是更好的主意。另请参阅:http://api.jquery.com/jquery.ajax/ – BonifatiusK 2014-11-13 12:17:42
jsonp不适用于POST请求 – 2015-05-20 10:16:16
与Laravel结合使用这个解决我的问题。只需将此标题添加到您的jQuery请求Access-Control-Request-Headers: x-requested-with
并确保您的服务器端响应具有此标头集Access-Control-Allow-Headers: *
。
没有理由手动将CORS头添加到请求中。浏览器将始终将CORS标题添加到您的请求中。 – 2014-04-13 12:50:02
真正的挑战是让服务器用正确的'Access-Control-Allow-Headers'和JQ提供正确的'Access-Control-Request-Headers'(加上任何你通过代码添加的内容)回复,这两者都不能是通配符。它只需要一个“坏”头来炸开飞行前,例如,使用'If-None-Match'作为条件GET,如果服务器没有列出。 – 2017-06-08 17:36:02
嗯,我这个问题挣扎了几个星期。
的最简单,最符合和不哈克的方式做到这一点是可能使用一个供应商的JavaScript API不使基于浏览器的调用,并能处理跨源请求。
例如Facebook JavaScript API和Google JS API。
如果您的API提供程序不是最新的,并且在其响应中不支持跨源资源源'*'标题,并且没有JS api(是的,我正在谈论关于您的雅虎),则会触发其中一个三个选项 -
在您的请求中使用jsonp,它向您的URL添加回调函数,您可以在其中处理响应。 买者这将改变请求URL所以你的API服务器必须具备处理?回调=在URL的结尾。
将请求发送到您的API控制器的API服务器,它与客户端位于同一个域中,或者启用了跨域资源共享,您可以将请求代理到第三方API服务器。
可能是最有用的,你正在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);
这是我所知道的真正POST的唯一途径来自JS的跨域。
JSONP将POST转换为GET,这可能会在服务器日志中显示敏感信息。
这对派对来说有点迟,但我一直在为此奋斗了几天。这是可能的,我在这里找到的答案都没有奏效。这看似简单。 这里的阿贾克斯电话:
<!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>
值得一提的是,Origin头部是一个请求头部,而不是一个响应头部。你的PHP脚本不应该设置它。 – Noodles 2016-11-24 22:36:23
哼。当我看到你在你的代码中创建了一个AJAX“GET”时,这让我很有希望,然后破灭了他们,当时OP很清楚地表示他试图避免使用“GET”并想使用“POST”。 – 2017-03-26 05:22:38
无论涉及什么动词,CORS标头的工作方式都是相同的。我们可以通过'$ .ajax()'针对正确配置的服务器调用所有动词。最难的部分是正确获取'Access-Control-Request-Headers',但即使这样也不困难。正如前面的海报所指出的,这不能是通配符,而是头文件的白名单。 – 2017-06-08 17:30:00
我花了一些时间来找到解决方案。
如果您的服务器响应正确和要求的问题,您应该在请求中添加withCredentials: true
到xhrFields
:
$.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要求
仍然不工作对我:( – 2017-09-18 10:50:23
jquery版本好吗?你设置'withCredentials:true'?你确定你有相关的头? – Dekel 2017-09-18 12:30:54
是的,1withCredential:true','jquery version:3.2.1'。其实它是通过邮递员工作,但它不通过浏览器 – 2017-09-18 13:49:01
出于某种原因,有关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>
是CORS需要如果两个Web服务器在同一台机器上? – jdigital 2011-04-21 23:48:09
据我所知,这是一个CORS请求,因为不同的端口。另外,OPTIONS请求表明浏览器正在将它视为CORS请求 – James 2011-04-22 03:02:50
[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