如何检测 JavaScript 中 XMLHttpRequest() 的跨域 (CORS) 错误与其他类型的错误
我正在尝试检测 XMLHttpRequest() 何时因跨域错误而不是错误请求而失败.例如:
I'm trying to detect when an XMLHttpRequest() fails due to a Cross Origin Error as opposed to a bad request. For example:
ajaxObj=new XMLHttpRequest()
ajaxObj.open("GET", url, true);
ajaxObj.send(null);
url考虑4种情况:
案例 1: url 是正确设置 access-control-allow-origin 的有效地址
Case 1: url is a valid address where access-control-allow-origin is properly set
- 示例:
http://192.168.8.35
我有一个服务器,其中Access-Control-Allow-Origin: *
在标头中设置 - 这很容易被检测为 ajaxObj.readyState==4 和 ajaxObj.status==200
- Example:
http://192.168.8.35
where I have a server withAccess-Control-Allow-Origin: *
set in the header - This is easy to detect as ajaxObj.readyState==4 and ajaxObj.status==200
案例 2: url 是现有服务器上的无效地址
Case 2: url is an invalid address at an existing server
- 示例:
http://xyz.google.com
服务器响应但不是有效请求的位置 - 这会导致 ajaxObj.readyState==4 和 ajaxObj.status==0
- Example:
http://xyz.google.com
where the server responds but it is not a valid request - This results in ajaxObj.readyState==4 and ajaxObj.status==0
案例 3: url 指向一个不存在的服务器 ip 地址
Case 3: url is to a non-existing server ip address
- 示例:
http://192.168.8.6
在我的本地网络上,没有任何响应 - 这会导致 ajaxObj.readyState==4 和 ajaxObj.status==0
- Example:
http://192.168.8.6
on my local network where there is nothing to respond - This results in ajaxObj.readyState==4 and ajaxObj.status==0
案例 4: url 是一个有效地址,其中 access-control-allow-origin 是 NOT 设置
Case 4: url is a valid address where access-control-allow-origin is NOT set
- 示例:
http://192.168.8.247
我有一个服务器 withoutAccess-Control-Allow-Origin: *
设置标题 - 这会导致 ajaxObj.readyState==4 和 ajaxObj.status==0
- Example:
http://192.168.8.247
where I have a server withoutAccess-Control-Allow-Origin: *
set in the header - This results in ajaxObj.readyState==4 and ajaxObj.status==0
问题是:如何区分案例 4(访问控制允许来源错误)和案例 2&3?
在案例 4 中,Chrome 调试控制台显示错误:
In Case 4, the Chrome debug console shows the error:
XMLHttpRequest 无法加载 http://192.168.8.247/.Access-Control-Allow-Origin 不允许来源 http://localhost.
如何在 Javascript 中显示该错误?
我试图在 ajaxObj
中找到一些指示,但与案例 2 和 3 相比似乎没有什么不同.
I tried to find some indication in ajaxObj
but nothing there seems to be different compared to Case 2&3.
这是我使用的一个简单测试:
Here is a simple test I used:
<!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>
使用 Chrome 的结果:
Results using Chrome:
Processing url=http://192.168.8.35
readyState=1
readyState=2
readyState=3
readyState=4, status=200
<小时>
Processing url=http://xyz.google.com
readyState=1
readyState=4, status=0
<小时>
Processing url=http://192.168.8.6
readyState=1
readyState=4, status=0
<小时>
Processing url=http://192.168.8.247
readyState=1
readyState=4, status=0
推荐答案
不,没有办法区分,根据 W3C 规范.
No, there is no way to tell the difference, according the W3C Spec.
以下是 CORS 规范如何指定 简单跨域请求 程序:
Here's how the CORS specification specifies the simple cross-origin request procedure:
应用发出请求的步骤并在发出请求时遵守以下请求规则.
Apply the make a request steps and observe the request rules below while making the request.
如果手动重定向标志未设置并且响应的 HTTP 状态代码为 301、302、303、307 或 308:应用重定向步骤.
如果最终用户取消请求:应用中止步骤.
如果出现网络错误:如果出现 DNS 错误、TLS 协商失败或其他类型的网络错误,应用网络错误步骤强>.不要请求任何类型的最终用户交互...
If there is a network error: In case of DNS errors, TLS negotiation failure, or other type of network errors, apply the network error steps. Do not request any kind of end user interaction...
否则:执行资源共享检查.如果返回失败,请应用网络错误步骤...
Otherwise: Perform a resource sharing check. If it returns fail, apply the network error steps...
在网络连接失败或 CORS 交换失败的情况下,应用了网络错误步骤,因此实际上无法区分这两种情况.
In the case of either a failed network connection or a failed CORS exchange, the network error steps are applied, so there is literally no way to distinguish between the two cases.
为什么?一个好处是它可以防止攻击者检查 LAN 的网络拓扑.例如,恶意网页脚本可以通过请求其 HTTP 接口找到路由器的 IP 地址,从而了解有关您的网络拓扑的一些信息(例如,您的私有 IP 块有多大,/8
或 /16
).由于您的路由器不(或不应该)发送 CORS 标头,因此脚本绝对不会学到任何东西.
Why? One benefit is that it prevents an attacker from inspecting the network topology of a LAN. For example, a malicious Web page script could find the IP address of your router by requesting its HTTP interface and therefore learn a few things about your network topology (e.g., how big your private IP block is, /8
or /16
). Since your router doesn't (or shouldn't) send CORS headers, the script learns absolutely nothing.
相关文章