XMLHttpRequest causes two network events - javascript

I'm noticing when I have use a XMLHttpRequest in my script, that for each time it gets called two events appear in Chrome's network waterfall.
The first event has a type xhr and a size of around ~27bytes and the second event has a type of text/html and a size of 0bytes.
I've noticed it in the past and have looked over it, but now I'm noticing its causing the page it connects to for it to run twice.
Is this normal? Did I implement something incorrectly?
function example(){
console.log('ran'); // this shows the function only ran once
var form = new FormData(), xml = new XMLHttpRequest();
form.append('test', '...');
xml.upload.onprogress = function(e){something.style.width = (e.loaded*100/e.total) + "%";}
xml.onload = function(){alert('done');}
xml.open('POST', 'https://externaldomainexample.net', true);
xml.send(form);
}

The two requests are being made because you are making a request to a different domain from which your page is hosted (cross origin). If you enable the "method" column in Chrome's network tab you'll see that the first request is an OPTIONS request, whereas the second is your POST request.
The first request is what's known as a Preflight request and asks the remote server what remote hosts are allowed to connect and what methods they are allowed to call. If this step fails, then you'll see an error in the browser saying the request has been "blocked by CORS policy".
If the preflight request is successful, then the second (POST) request is made.
Depending on how the server is configured, you may need to have it handle OPTIONS requests differently, so that it doesn't perform the same action twice.

Related

spurious ajax OPTIONS request being made along with a GET request

I am making a standard ajax request with the code below
let x = new XMLHttpRequest();
x.onload = function(event) { …};
x.open("GET", url, true);
x.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
x.send();
The problem is that, for some reason I can't fathom, two ajax requests are made. The first one is an OPTIONS request and the second one is the GET request that I actually wanted. Any idea why?
My server is a nodejs app which I am starting using nodemon which restarts the server if it senses index.js has changed (this is helpful in development when you don't want to stop and restart the server). With this OPTIONS business, nodemon thinks my index.js has changed and restarts nodejs.
Additionally, the OPTIONS request results in a successful request that returns http 200. But, nothing is returned to the web page that initiated that ajax request in the first place (this could be that immediately after the OPTIONS request, nodejs is restarted by nodemon. Then the GET request is repeated, also with 200, and the web page gets the result
The problem is that, for some reason I can't fathom, two ajax requests are made. The first one is an OPTIONS request and the second one is the GET request that I actually wanted. Any idea why?
Because you're making a cross-origin call (for instance, from http://localhost to http://localhost:someport), which is normally disallowed by the Same Origin Policy. So the browser sends a "pre-flight" OPTIONS request to see if the server wants to allow the call via Cross-Origin Resource Sharing.

Redirect Failing on CORS Request

I'm trying to download a file in client-side Javascript using the Box API, which redirects the request to a temporary download link once the file has been found. The browser is blocking the redirect, though, throwing the following error:
XMLHttpRequest cannot load https://api.box.com/2.0/files/file-id/content. The request was redirected to 'https://dl.boxcloud.com/d/1/some-big-hash/download', which is disallowed for cross-origin requests that require preflight.
In the Network console I see three requests, the first is an OPTIONS (which must be the pre-flight because the actual code sends a GET) with a 200 response, and the second two are identical GET requests which both get 302'd (the expected response for that API call). Here's the code that makes the request:
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.setRequestHeader('Authorization', 'Bearer '+MyToken);
xhr.onload = function()
{
//some stuff
}
xhr.onerror = function()
{
//some other stuff
}
xhr.send();
My question is (a): Why are two GETs being sent after the preflight comes back?
And (b): Is there any way I can format the request to allow following the redirect? And (c) if not, can I at least retrieve the redirect URL from the response and follow it with another explicit request? Every response in the console has the 'Access-Control-Allow-Origin' header set with the correct origin.
Thanks
I don't understand why you get three rather than two requests, but the way CORS has worked thus far is that a request with a preflight cannot be redirected. This has changed in the Fetch Standard, but user agents have not yet picked up the change.

Why does my XMLHttpRequest have readystate 4 but status 0?

I have a content script in my Chrome extension which runs on some HTTPS page. It is trying to send a POST request to an HTTP page (by means of a background script) which is a route for an API that I have set up. I am trying to send JSON data over. However I am getting status 0, even though the ready state is 4. I used Postman to perform the same post and it worked. This leads me to believe it is a HTTPS protocol issue, however I am performing a GET on an HTTP page in the same background script and that is working fine. What might be the issue then? Here is my POST code:
var string = json;
xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var json = JSON.parse(xhr.responseText);
}
};
xhr.send(string);
Thanks!
UPDATE:
I used the chrome developer tools to debug the background script and I found the error, which was "Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.". I guess background script errors do not print to the main console.
UPDATE:
I had to add the site I was posting to to the permissions field in my manifest. It works now.
I have a similar issue and, after debugging it for days, the only solution I found was to make the XMLHttpRequest synchronous by setting set the async param in the XMLHttpRequest open method to false.
The readyState value of 4 means the operation completed successfully or failed. The status property is initialized to 0 and will remain at 0 if an error occurs. Assign an event handler to the xhr.onerror property and I bet you'll see that handler fire. Unfortunately, the error event doesn't give any useful information about what caused the error.
To find out what caused the error, I would use the debug tools found in Chrome. Menu => More tools => Developer Tools. Then go to the "Network" tab. There you can see all the HTTP requests your webpage has made. It will show better details on any errors there.
What did you do?
I had to add the site I was posting to the permissions field in my manifest. It works now.
XMLHttpRequest.setRequestHeader("Access-Control-Allow-Origin", "the api website"); ?

AJAX request doesn't send Cookies set from same domain

I'm developing a sort of user-tracking system, that works as follows:
1) A webmaster adds a js script in his website:
<script src="http://example.com/in/tracking.js"></script>
2) When a user loads the page, the javascript request send back a cookie in response:
Set-Cookie:trackid=c1d7fde9cf87a9501cea57cedde97998;Version=1;Comment=;Domain=example.com;Path=/;Max-Age=31556926
(it's basically a simple cookie that lasts for 1 year)
3) The tracking.js makes a POST XMLHttpRequest, to the same example.com domain, passing some parameters:
theAjaxRequest.open("POST","http://example.com/in",true);
theAjaxRequest.setRequestHeader("Content-type", "multipart/form-data");
theAjaxRequest.send(parameters);
4) The backend of example.com should then read the previously set "trackid" cookie, but, instead, I get no cookies on request... By analyzing the POST request via Chrome inspector, I noted that no cookies are passed in request headers (while the first GET request for tracking.js sets correctly the cookie via Set-Cookie).
How come? At first I assumed it may be a problem related to same-origin-policy; so I enabled CORS headers on back-end web server. No results. So, I tried to load tracking.js on a website under same domain of example.com (say web.example.com). Anyway, no results again...
Am I missing something?
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain(){
if(invocation) {
invocation.open('GET', url, true);
invocation.withCredentials = true;
invocation.onreadystatechange = handler;
invocation.send();
}
Line 7 shows the flag on XMLHttpRequest that has to be set in order to make the invocation with Cookies, namely the withCredentials boolean value. By default, the invocation is made without Cookies. Since this is a simple GET request, it is not preflighted, but the browser will reject any response that does not have the Access-Control-Allow-Credentials: true header, and not make the response available to the invoking web content.

CORS AJAX Call not Successful

I have an AJAX call trying to execute the following CORS request to a Web Server (I am currently testing using only the latest version of Chrome):
var xhr = new XMLHttpRequest();
xhr.open("get", "http://www.web_server_url.com/query", true);
xhr.onload = function(){
};
xhr.send(null);
Meanwhile, I am still getting the following message:
XMLHttpRequest cannot load http://www.web_server_url.com/query. Origin http://localhost is not allowed by Access-Control-Allow-Origin.
Would someone know what I am missing?
The reason is exactly what it says in the error: The server at www.web_server_url.com is not allowing the localhost origin. It's up to the server to decide whether to allow the origin of the call. In this case, apparently it's not allowing it.
The way CORS works, the server replies to the request (or a "preflight" request) with headers either allowing or disallowing the origin on the basis of the information the browser sends it.

Categories

Resources