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);
Consider 4 cases for url:
Case 1: url is a valid address where access-control-allow-origin is properly set
http://192.168.8.35
where I have a server with Access-Control-Allow-Origin: *
set in the headerCase 2: url is an invalid address at an existing server
http://xyz.google.com
where the server responds but it is not a valid requestCase 3: url is to a non-existing server ip address
http://192.168.8.6
on my local network where there is nothing to respondCase 4: url is a valid address where access-control-allow-origin is NOT set
http://192.168.8.247
where I have a server without Access-Control-Allow-Origin: *
set in the headerThe problem is: How do I differentiate Case 4 (access-control-allow-origin error) and Cases 2&3?
In Case 4, the Chrome debug console shows the error:
XMLHttpRequest cannot load http://192.168.8.247/. Origin http://localhost is not allowed by Access-Control-Allow-Origin.
How do I make that error known in Javascript?
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>
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
To differentiate a CORS violation from other failed AJAX requests, you can inspect the response headers of a HEAD request using server-side code and pass the results back to your client page. For example, if the AJAX request fails (status 0), you could call this script (let's call it cors.
The Cross-Origin Resource Sharing (CORS) specification consists of a simple header exchange between client-and-server, and is used by IE8's proprietary XDomainRequest object as well as by XMLHttpRequest in browsers such as Firefox 3.5 and Safari 4 to make cross-site requests.
Cross-Origin Resource Sharing (CORS) errors occur when a server doesn't return the HTTP headers required by the CORS standard. To resolve a CORS error from an API Gateway REST API or HTTP API, you must reconfigure the API to meet the CORS standard.
You can test it with any rest client like POSTMAN Rest Client, or simply you can check it from browser console - > Network tab -> in xhr filter - check the header for the particular request.
No, there is no way to tell the difference, according the W3C Spec.
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.
If the manual redirect flag is unset and the response has an HTTP status code of 301, 302, 303, 307, or 308: Apply the redirect steps.
If the end user cancels the request: Apply the abort steps.
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...
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.
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.
Maybe in case it helps anyone... one other way to handle difference between cors and network error... can work with chrome or firefox... (not perfect solution though)
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 }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With