119

Cannot get data with XMLHttpRequest (status 0 and responseText is empty):

xmlhttp=new XMLHttpRequest();
xmlhttp.open("GET","http://www.w3schools.com/XML/cd_catalog.xml", true);
xmlhttp.onreadystatechange=function() 
{
  if(xmlhttp.readyState==4)
    alert("status " + xmlhttp.status);
}
xmlhttp.send();

It alerts "status 0".

The same situation with the localhost request (cd_catalog.xml is saved as a local file)

xmlhttp.open("GET","http://localhost/cd_catalog.xml", true);

But with the localhost IP request

xmlhttp.open("GET","http://127.0.0.1/cd_catalog.xml", true);

and with the local file request

xmlhttp.open("GET","cd_catalog.xml", true);

everything is OK (status 200)

What can cause the problem (status=0) with the online request?

PS: Live HTTP Headers shows that everything is OK in all 4 cases:

  HTTP/1.1 200 OK
  Content-Length: 4742

PS2: Apache local web server on VMWare (host OS Win7, Guest OS Ubuntu, Network adapter – NAT). Browser – Firefox.

sdo
  • 652
  • 3
  • 13
arigasa
  • 1,191
  • 2
  • 8
  • 3
  • 1
    Is your test page at `http://127.0.0.1` by any chance? ;) – Roatin Marth Feb 15 '11 at 16:00
  • Yes. http://127.0.0.1/CDCatalogTest.html – arigasa Feb 15 '11 at 16:06
  • 8
    You answered your question. `XMLHttpRequest` can't do cross-domain requests. There are some workarounds though. Look at jquery, for example. – meze Feb 15 '11 at 16:15
  • 2
    @meze: Cross-domain calls work with jQuery. But how can it not work with plain JavaScript, as jQuery is implemented in JavaScript? It makes no sense to me. Is jQuery using some kind of nasty workaround? – Gruber Dec 12 '12 at 16:17
  • @Gruber JSONP and CORS. The latter isn't supported by some browsers, like IE < 8. And btw the docs of jquery say: `Due to browser security restrictions, most "Ajax" requests are subject to the same origin policy; the request can not successfully retrieve data from a different domain, subdomain, or protocol.`. – meze Dec 12 '12 at 21:57
  • @meze: I just learned I was wrong to say that jQuery cross-site calls works. Thanks for clarifying. – Gruber Dec 13 '12 at 08:33
  • Use php to get the file. Little work-around: http://jquery-howto.blogspot.com/2009/04/cross-domain-ajax-querying-with-jquery.html –  Feb 15 '11 at 16:19
  • I've implemented the preflight CORS and still seeing this status code as 0? – Weishi Z Jun 24 '16 at 03:12
  • Does this answer your question? [Does an HTTP Status code of 0 have any meaning?](https://stackoverflow.com/questions/3825581/does-an-http-status-code-of-0-have-any-meaning) – Michael Freidgeim Dec 24 '21 at 05:14

21 Answers21

62

status is 0 when your html file containing the script is opened in the browser via the file scheme. Make sure to place the files in your server (apache or tomcat whatever) and then open it via http protocol in the browser. (i.e. http://localhost/myfile.html) This is the solution.

YakovL
  • 7,557
  • 12
  • 62
  • 102
Abhishek_8
  • 641
  • 5
  • 2
  • 1
    Why is this being downvoted? It is actually true! XHR requests from file:// URLs of files also on file:// URLs actually have status == 0 on success (tested on FF 24.0.5). – Daniel Roethlisberger Dec 31 '14 at 21:20
  • 3
    I'm also getting status == 0 on success on Safari Version 6.1.6. – Planar Feb 22 '15 at 08:01
  • I'm having status=0 (but status 200 on network) using _Load temporary add-on_ on firefox – JobaDiniz Aug 22 '17 at 17:24
  • 1
    still valid answer. HTTP response is 200 for actual remote schemes (http et al.) and 0 for local file (`file://` scheme). Obviously, you need to allow local file loading first by disabling CORS. – pid Nov 08 '19 at 13:52
  • @DanielRoethlisberger FYI your answer does not build anymore – jdero Jan 05 '22 at 00:12
  • @jdero This isn't my anwer. Also, it seems like a bit of a stretch to expect answers to still be valid ten years down the road :) – Daniel Roethlisberger Jan 05 '22 at 11:40
  • @DanielRoethlisberger Apologies for the mistag- and yes I think I even commented on the wrong answer here. Sorry for the mixup – jdero Jan 06 '22 at 21:58
33

The cause of your problems is that you are trying to do a cross-domain call and it fails.

If you're doing localhost development you can make cross-domain calls - I do it all the time.

For Firefox, you have to enable it in your config settings

signed.applets.codebase_principal_support = true

Then add something like this to your XHR open code:

  if (isLocalHost()){
    if (typeof(netscape) != 'undefined' && typeof(netscape.security) != 'undefined'){
      netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');
    }
  }

For IE, if I remember right, all you have to do is enable the browser's Security setting under "Miscellaneous → Access data sources across domains" to get it to work with ActiveX XHRs.

IE8 and above also added cross-domain capabilities to the native XmlHttpRequest objects, but I haven't played with those yet.

Greg Dubicki
  • 5,983
  • 3
  • 55
  • 68
Slammer
  • 331
  • 2
  • 2
  • 8
    In case anyone needs it, for Chrome you need to launch a new instance of it (without any already open) and use `--allow-file-access-from-files` – TheZ Jun 23 '12 at 02:57
  • @TheZ: Are you 100%? I've heard that you only need to run new instance of Chrome, with `--allow-file-access-from-files` switch, but you **don't have to** close all other running instances. Exactly like in case of _Chrome Incognito Mode_ -- you can use it, without closing any other running instances. – trejder Jul 23 '13 at 08:39
  • It looks like support for 'UniversalBrowserRead' has been dropped, so this work around is not an option. – Loren_ Oct 09 '15 at 03:40
  • Also, it could happen when you requesting http page from https page (like in-browser extension). – sibvic Mar 15 '18 at 13:41
  • I'm encountering this problem, **despite** the html page and the AJAX script residing in the same domain. But weirdly, it's only affecting **some** scripts, most notably any scripts that access MongoDB resources. Any clues as to why this is? – David Edwards Aug 15 '18 at 19:05
26

Actually make sure your button type is Button not Submit, that caused status conflict where I met recently.

dyuan
  • 261
  • 3
  • 2
  • 1
    There's a conflict because submitting a form has some default behavior that you need to prevent if you're handling the event and making an ajax call yourself. You can prevent the default behaviour by taking the event in your handler and calling `e.preventDefault()` – Jordan May 05 '15 at 19:29
22

If the server responds to an OPTIONS method and to GET and POST (whichever of them you're using) with a header like:

Access-Control-Allow-Origin: *

It might work OK. Seems to in FireFox 3.5 and rekonq 0.4.0. Apparently, with that header and the initial response to OPTIONS, the server is saying to the browser, "Go ahead and let this cross-domain request go through."

robsch
  • 9,358
  • 9
  • 63
  • 104
Alex Robinson
  • 599
  • 4
  • 4
  • 3
    This is the right answer! Look at http://en.wikipedia.org/wiki/Cross-origin_resource_sharing for more info. If you add this header, it is not 'might work', but 'will work'. NB What you need to add is an HTTP /response/ header - so you can only do this on a server which you control. It will never be possible to directly fetch http://www.w3schools.com/XML/cd_catalog.xml using `XMLHttpRequest` (i.e. as per the original question), because that resource does not (at least, as of 24 Apr 2015) include any such CORS header. – MikeBeaton Apr 24 '15 at 08:52
16

Consider also the request timeout:

Modern browser return readyState=4 and status=0 if too much time passes before the server response.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • 3
    @AndreaSavojardo: Do you have any reference (like a post on MDN) on whether this behavior complies with the standards? – Alexander Abakumov Feb 06 '18 at 17:02
  • @AndreaSavojardo I have readyState=4 and status=0 and the server is not running but the error's alert is showed me fast....how much time passes for "request time out"? –  Dec 21 '19 at 16:39
  • What are you talking about. ReadyState=4 means finished, the docs say it very clearly https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState – Artem Novikov Sep 10 '21 at 17:53
  • `DONE The fetch operation is complete. This could mean that either the data transfer has been completed successfully or failed.` So done (ReadyState=4) could mean it failed, which could be because of a timeout, at least in my case it stopped happening after increasing the timeout – Guiorgy Jul 17 '23 at 17:04
7

Add setRequestHeader("Access-Control-Allow-Origin","*") to your server response.

Geo
  • 3,160
  • 6
  • 41
  • 82
Ivan
  • 71
  • 1
  • 1
4

Open javascript console. You'll see an error message there. In my case it was CORS.

Jarekczek
  • 7,456
  • 3
  • 46
  • 66
4

I had faced a similar problem. Every thing was okay, the "readystate" was 4, but the "status" was 0. It was because I was using a Apache PHP portable server and my file in which I used the "XMLHttpRequest" object was a html file. I changed the file extension to php and the problem was solved.

Reyan
  • 41
  • 1
3

To see what the problem is, when you get the cryptic error 0 go to ... | More Tools | Developer Tools (Ctrl+Shift+I) in Chrome (on the page giving the error)

Read the red text in the log to get the true error message. If there is too much in there, right-click and Clear Console, then do your last request again.

My first problem was, I was passing in Authorization headers to my own cross-domain web service for the browser for the first time.

I already had:

Access-Control-Allow-Origin: *

But not:

Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization

in the response header of my web service.

After I added that, my error zero was gone from my own web server, as well as when running the index.html file locally without a web server, but was still giving errors in code pen.

Back to ... | More Tools | Developer Tools while getting the error in codepen, and there is clearly explained: codepen uses https, so I cannot make calls to http, as the security is lower.

I need to therefore host my web service on https.

Knowing how to get the true error message - priceless!

Maya
  • 421
  • 6
  • 12
  • I used this approach (f12 in chrome) and found out I was trying to go from https to http which was silently failing without providing anything useful. **ERROR MESSAGE: VM1152:1 Mixed Content: The page at `'https://mysiteoriginsite'` was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint `'http://MyDestinationSite/MyService.svc'`. This request has been blocked; the content must be served over HTTPS.** – GrayDwarf Mar 29 '19 at 17:10
2

To answer the question of why http://127.0.0.1/cd_catalog.xml works while http://localhost/cd_catalog.xml doesn't: Firefox is treating 127.0.0.1 and localhost as two different domains.

Tomi Aarnio
  • 2,446
  • 1
  • 19
  • 14
1

Here's another case in which status === 0, specific to uploading:

If you attach a 'load' event handler to XHR.upload, as suggested by MDN (scroll down to the upload part of 'Monitoring progress'), the XHR object will have status=0 and all the other properties will be empty strings. If you attach the 'load' handler directly to the XHR object, as you would when downloading content, you should be fine (given you're not running off localhost).

However, if you want to get good data in your 'progress' event handlers, you need to attach a handler to XHR.upload, not directly to the XHR object itself.

I've only tested this so far on Chrome OSX, so I'm not sure how much of the problem here is MDN's documentation and how much is Chrome's implementation...

ericsoco
  • 24,913
  • 29
  • 97
  • 127
1

Alex Robinson already (and first) gives the correct answer to this issue. But to elaborate it a little more...

You must add the HTTP response header:

Access-Control-Allow-Origin: *

If you do this, the result is not just 'might work', but 'will work'.

NB What you need to add is an HTTP response header - so you can only do this on a server which you control. It will never be possible to directly fetch http://w3schools.com/XML/cd_catalog.xml from its original URL using an XMLHttpRequest (as per OP's question), because that resource does not (at least, not as of 24 Apr 2015) include any such CORS header.

http://en.wikipedia.org/wiki/Cross-origin_resource_sharing gives more info.

MikeBeaton
  • 3,314
  • 4
  • 36
  • 45
0

My problem similar to this was solved by checking my html code. I was having an onclick handler in my form submit button to a method. like this : onclick="sendFalconRequestWithHeaders()". This method in turn calls ajax just like yours, and does what I want. But not as expected, my browser was returning nothing.

Learned From someone's hardwork, I have returned false in this handler, and solved. Let me mention that before arriving to this post, I have spent a whole 3-day weekend and a half day in office writing code implementing CORS filters, jetty config, other jersey and embedded jetty related stuff - just to fix this., revolving all my understanding around cross domain ajax requests and standards stuff. It was ridiculous how simple mistakes in javascript make you dumb.

To be true, I have tried signed.applets.codebase_principal_support = true and written isLocalHost() **if**. may be this method needs to be implemented by us, firefox says there is no such Now I have to clean my code to submit git patch cleanly. Thanks to that someone.

Siva Tumma
  • 1,695
  • 12
  • 23
0

A browser request "127.0.0.1/somefile.html" arrives unchanged to the local webserver, while "localhost/somefile.html" may arrive as "0:0:0:0:0:0:0:1/somefile.html" if IPv6 is supported. So the latter can be processed as going from a domain to another.

0

Alex Robinson and bmju provided valuable information to understand cross-origin issues. I wanted to add that you may need to make an explicit OPTIONS call in your client code before making the desired GET/POST (e.g. against a CORS OAuth service endpoint). Your browser/library may not automatically handle the OPTIONS request. Gruber, this is one of the possible answers to your question.

0

I had the same problem (readyState was 4 and status 0), then I followed a different approach explained in this tutorial: https://spring.io/guides/gs/consuming-rest-jquery/

He didn't use XMLHttpRequest at all, instead he used jquery $.ajax() method:

<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="hello.js"></script>
</head>

<body>
    <div>
        <p class="greeting-id">The ID is </p>
        <p class="greeting-content">The content is </p>
    </div>
</body>

and for the public/hello.js file (or you could insert it in the same HTML code directly):

$(document).ready(function() 
 {
    $.ajax({
        url: "http://rest-service.guides.spring.io/greeting"
   }).then(function(data) {
      $('.greeting-id').append(data.id);
      $('.greeting-content').append(data.content);
   });
 });
RMDev
  • 163
  • 1
  • 11
0

I had to add my current IP address (again) to the Atlas MongoDB whitelist and so got rid of the XMLHttpRequest status 0 error

Anja
  • 473
  • 4
  • 12
0

bottle app in python:

@route('/mazer2/get', method='POST')
def GetMaze2():
    if MazeCore == None: abort(666, "MazeCore поломался :///")
    Check()
    Comm = request.body.read().decode("utf-8")
    Map = MazeCore.GetMaze2(Comm, TestToken2())
    response.headers["Access-Control-Allow-Origin"] = "*" #Here ;'-} It helped me
    return Map
VectorASD
  • 11
  • 2
0

I had the same problem when I tried to consume some web methods created by python in a flask environment, by XMLHttpRequest. After inspecting the firefox console, I realised that the cause of problem was Same Origin Policy, which prevents calling web methods of a different ORIGIN (An Origin consists of a 3 part tuple including: protocol, domain, and port number). For me, the solution was to use CORS, and fortunately there is a python package named flask-cors which I used and everything works fine.

Ehsan
  • 11
  • 2
-1

I just had this issue because I used 0.0.0.0 as my server, changed it to localhost and it works.

Vad
  • 4,052
  • 3
  • 29
  • 34
-4

Edit: Please read Malvolio's comments below as this answer's knowledge is outdated.

You cannot do cross-domain XMLHttpRequests.

The call to 127.0.0.1 works because your test page is located at 127.0.0.1, and the local test also works since, well... it's a local test.

The other two tests fail because JavaScript cannot communicate with a distant server through XMLHttpRequest.

You might instead consider either:

  • XMLHttp-request your own server to fetch your remote XML content for you (php script, for example)
  • Trying to use a service like GoogleAppEngine if you want to keep it full JavaScript.

Hope that helps

Gabriel S.
  • 1,961
  • 2
  • 20
  • 30
  • 40
    This is just wrong. You *can* do cross-domain XMLHttpRequests. – Michael Lorton May 09 '12 at 18:15
  • 1
    "You cannot" as in "You shouldn't do it because it's never a good idea" – Gabriel S. Jul 24 '12 at 09:53
  • 24
    -- fair enough, but I don't know if a comment is the *best* forum for that. Cross-domain XMLHttpRequests certainly do have some security challenges but they offer all the tools necessary to deal with those challenges. That aside, they allow websites to offer services to other websites easily, to use CDNs to propagate data, and to respond more quickly to user requests. If you have any specific questions, you can message me, or better, post a question here on SO and draw my attention to it. – Michael Lorton Jul 24 '12 at 15:41
  • 2
    @GabrielSprenger: Cross-domain `XMLHttpRequest`s is not only a **good** idea, it's so common nowadays that NOT doing them in a modern web app (beyond some kind of HelloWorlds) is something ridiculous. Any external REST service that your app consumes requires a cross-domain `XMLHttpRequest`. And that's why all that CORS stuff was added. – Alexander Abakumov Feb 06 '18 at 17:09