use*_*305 51 javascript ajax xmlhttprequest cors
我试图检测XMLHttpRequest()由于交叉原始错误而不是错误请求而失败.例如:
ajaxObj=new XMLHttpRequest()
ajaxObj.open("GET", url, true);
ajaxObj.send(null);
Run Code Online (Sandbox Code Playgroud)
考虑4个网址案例:
情况1: url是正确设置access-control-allow-origin的有效地址
http://192.168.8.35我Access-Control-Allow-Origin: *在标头中设置了一个服务器情况2: url是现有服务器上的无效地址
http://xyz.google.com服务器响应的位置,但它不是有效请求情况3: url是一个不存在的服务器IP地址
http://192.168.8.6在我的本地网络上没有任何响应案例4: URL是一个有效的地址在访问控制允许来源是不设置
http://192.168.8.247我在标头中没有 Access-Control-Allow-Origin: *设置的服务器问题是:如何区分案例4(访问控制允许来源错误)和案例2和3?
在案例4中,Chrome调试控制台显示错误:
XMLHttpRequest cannot load http://192.168.8.247/. Origin http://localhost is not allowed by Access-Control-Allow-Origin.
如何在Javascript中识别该错误?
我试图找到一些迹象,ajaxObj但与案例2和3相比似乎没有什么不同.
这是我使用的简单测试:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>CORS Test</title>
<script type="text/javascript">
function PgBoot()
{
// doCORS("http://192.168.8.35"); // Case 1
// doCORS("http://xyz.google.com"); // Case 2
doCORS("http://192.168.8.6"); // Case 3
// doCORS("http://192.168.8.247"); // Case 4
}
function doCORS(url)
{
document.getElementById("statusDiv").innerHTML+="Processing url="+url+"<br>";
var ajaxObj=new XMLHttpRequest();
ajaxObj.overrideMimeType('text/xml');
ajaxObj.onreadystatechange = function()
{
var stat=document.getElementById("statusDiv");
stat.innerHTML+="readyState="+ajaxObj.readyState;
if(ajaxObj.readyState==4)
stat.innerHTML+=", status="+ajaxObj.status;
stat.innerHTML+="<br>";
}
ajaxObj.open("GET", url, true);
ajaxObj.send(null);
}
</script>
</head>
<body onload="PgBoot()">
<div id="statusDiv"></div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
使用Chrome的结果:
Processing url=http://192.168.8.35
readyState=1
readyState=2
readyState=3
readyState=4, status=200
Run Code Online (Sandbox Code Playgroud)
Processing url=http://xyz.google.com
readyState=1
readyState=4, status=0
Run Code Online (Sandbox Code Playgroud)
Processing url=http://192.168.8.6
readyState=1
readyState=4, status=0
Run Code Online (Sandbox Code Playgroud)
Processing url=http://192.168.8.247
readyState=1
readyState=4, status=0
Run Code Online (Sandbox Code Playgroud)
aps*_*ers 41
不,根据W3C规范,没有办法区分.
以下是CORS规范如何指定简单的跨源请求过程:
在发出请求时,应用make a request步骤并遵守下面的请求规则.
如果未设置手动重定向标志且响应的HTTP状态代码为301,302,303,307或308:应用重定向步骤.
如果最终用户取消请求:应用中止步骤.
如果存在网络错误:如果出现 DNS错误,TLS协商失败或其他类型的网络错误,请应用网络错误步骤.不要求任何类型的最终用户交互......
否则:执行资源共享检查.如果它返回失败,请应用网络错误步骤 ...
在网络连接失败或CORS交换失败的情况下,应用网络错误步骤,因此实际上无法区分这两种情况.
为什么?一个好处是它可以防止攻击者检查LAN的网络拓扑.例如,恶意网页脚本可以通过请求其HTTP接口找到路由器的IP地址,从而了解有关网络拓扑的一些信息(例如,您的私有IP块有多大,/8或者/16).由于您的路由器没有(或不应该)发送CORS标头,因此脚本完全没有学到任何东西.
也许万一它可以帮助任何人...另一种方法来处理cors和网络错误之间的差异...可以使用chrome或firefox ...(虽然不是完美的解决方案)
var external = 'your url';
if (window.fetch) {
// must be chrome or firefox which have native fetch
fetch(external, {'mode':'no-cors'})
.then(function () {
// external is reachable; but failed due to cors
// fetch will pass though if it's a cors error
})
.catch(function () {
// external is _not_ reachable
});
} else {
// must be non-updated safari or older IE...
// I don't know how to find error type in this case
}
Run Code Online (Sandbox Code Playgroud)
要将CORS违规与其他失败的AJAX请求区分开来,可以使用服务器端代码检查HEAD请求的响应标头,并将结果传递回客户端页面。例如,如果AJAX请求失败(状态0),则可以调用此脚本(让我们调用它cors.php),并确定响应头是否包含Access-Control-*头。
例子:
cors.php?url = http://ip.jsontest.com
cors.php?url = http://www.google.com
cors.php?url = http://10.0.0.1
退货
HTTP / 1.1 200 OK访问控制允许来源:*
HTTP / 1.1 302找到
无效的请求
cors.php-根据需要自定义
<?php /* cors.php */
$url = $_GET["url"];
if(isset($url)) {
$headers = getHeaders($url);
header("Access-Control-Allow-Origin: *");
if(count($headers) == 0) {
die("Invalid request"); // cURL returns no headers on bad urls
} else {
echo $headers[0]; // echo the HTTP status code
}
// Include any CORS headers
foreach($headers as $header) {
if(strpos($header, "Access-Control") !== false) {
echo " " . $header;
}
}
}
function getHeaders($url, $needle = false) {
$headers = array();
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 4); // Timeout in seconds
curl_setopt($ch, CURLOPT_TIMEOUT, 4); // Timeout in seconds
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'HEAD'); // HEAD request only
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $header) use(&$headers) {
array_push($headers, $header);
return strlen($header);
});
curl_exec($ch);
return $headers;
} /* Drakes, 2015 */
Run Code Online (Sandbox Code Playgroud)
客户端测试工具:
function testCORS(url, $elem) {
$.ajax({
url: url,
timeout: 4000
})
.fail(function(jqXHR, textStatus) {
if(jqXHR.status === 0) {
// Determine if this was a CORS violation or not
$.ajax({
context: url,
url: "http://myserver.com/cors.php?url=" + escape(this.url),
})
.done(function(msg) {
if(msg.indexOf("HTTP") < 0) {
$elem.text(url + " - doesn't exist or timed out");
} else if(msg.indexOf("Access-Control-Allow-Origin") >= 0) {
$elem.text(url + " - CORS violation because '" + msg + "'");
} else {
$elem.text(url + " - no Access-Control-Allow-Origin header set");
}
});
} else {
// Some other failure (e.g. 404), but not CORS-related
$elem.text(url + " - failed because '" + responseText + "'");
}
})
.done(function(msg) {
// Successful ajax request
$elem.text(this.url + " - OK");
}); /* Drakes, 2015 */
}
Run Code Online (Sandbox Code Playgroud)
线束驱动程序:
// Create a div and append the results of the URL calls
$div = $("<div>");
$("body").append($div);
var urls = ["http://ip.jsontest.com", "http://google.com", "http://10.0.0.1"];
urls.map( function(url) {
testCORS(url, $div.append("<h4>").children().last());
});
Run Code Online (Sandbox Code Playgroud)
结果:
http://ip.jsontest.com-确定
http://google.com-未设置Access-Control-Allow-Origin标头
http://10.0.0.1-不存在或超时
令人惊讶的是,您可以对图像执行此操作(也许对于其他特定内容类型也有类似的解决方案)。诀窍在于,它显然不考虑 CORS,因此语句“url 无法通过 XHR 加载 && url 成功通过 img src 加载”意味着该 URL 有效,但被 CORS 阻止。
这肯定不会在所有情况下都有帮助,但在某些情况下(例如实用程序检测您是否正确传递 CORS)它可能会起作用。例如,如果我的应用程序(单独的前端和后端)安装了正确配置的后端 URL 并在服务器上错误配置了 CORS,我想在控制台中发出警告,所以这对我来说已经足够了,因为我可以提供图像来测试它在。
function testCors(url) {
var myRequest = new XMLHttpRequest();
myRequest.open('GET', url, true);
myRequest.onreadystatechange = () => {
if (myRequest.readyState !== 4) {
return;
}
if (myRequest.status === 200) {
console.log(url, 'ok');
} else {
var myImage = document.createElement('img');
myImage.onerror = (...args) => {console.log(url, 'other type of error', args);}
myImage.onload = () => {console.log(url, 'image exists but cors blocked');}
myImage.src = url;
console.log(url, 'Image not found');
}
};
myRequest.send();
}
Run Code Online (Sandbox Code Playgroud)