Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent preflight OPTIONS when using sub domains

Given two sub domains:

web.mysite.com and api.mysite.com

Currently making any request from web. to api. results in the preflight OPTIONS request being made. This wouldn't be so much of an issue if it didn't add an extra 600ms to requests in China.

I was told that setting document.domain = 'mysite.com'; in JS would resolve the issue but this hasn't helped at all.

Is it possible / how can I disable the OPTIONS request when sending to just a different sub domain.

like image 738
Phill Avatar asked Jul 17 '15 04:07

Phill


People also ask

How can we avoid preflight requests?

Another way to avoid Preflight requests is to use simple requests. Preflight requests are not mandatory for simple requests, and according to w3c CORS specification, we can label HTTP requests as simple requests if they meet the following conditions. Request method should be GET , POST , or HEAD .

What triggers a preflight request?

A preflight request is a small request that is sent by the browser before the actual request. It contains information like which HTTP method is used, as well as if any custom HTTP headers are present. The preflight gives the server a chance to examine what the actual request will look like before it's made.

Are preflight requests necessary?

Without the preflight, a user on a different domain could now issue a request to the API. The API would assume the request is valid (since it knows nothing of CORS) and execute the request. The browser could block the response from reaching the user, but at this point, the damage may already be done.

What does preflight mean in network tab?

Preflight requests are a mechanism introduced by the Cross-Origin Resource Sharing (CORS) standard used to request permission from a target website before sending it an HTTP request that might have side effects.


3 Answers

Solved this using the iframe technique which seems to be what Facebook / Twitter do.

Steps below:

1) Set the document.domain to be the root domain. So given the url http://site.mysite.com/ I set the domain in JavaScript like document.domain = 'mysite.com';

2) Setup an iframe which pulls a HTML file from the API Domain.

<iframe id="receiver" src="http://api.mysite.com/receiver" style="position:absolute;left:-9999px"></iframe>

This is set to be positioned so it can't be seen.

3) Set the HTML of the receiver page to set the domain:

<!DOCTYPE html><body><script>document.domain='mysite.com'</script></body></html>

4) Added an onload event to the iframe to capture the window once its loaded.

onload="window.tempIframeCallback()"

5) Assign the child window to a variable.

window.tempIframeCallback = function() {
  window.childWindow = window.receiver.contentWindow;
}

6) Make the XMLHttpRequest() from the childWindow instead of the main window.

var xhr = new window.childWindow.XMLHttpRequest();

Now all requests will be sent without a preflight OPTIONS request.


7) When using jQuery, you can also set the source of xhr in the settings:

$.ajax({
  ...
  xhr: function() {
    return new window.childWindow.XMLHttpRequest();
  }
});
like image 72
Phill Avatar answered Oct 22 '22 19:10

Phill


As a complement to @Phill's answer that deserves all the credits, here is the final html code, that also exposes the iframe's fetch function:

<!DOCTYPE html>
<html><body>
<script>
    document.domain = 'mysite.com';
    window.setupAPI = function() {
        var receiverWindow = window.receiver.contentWindow;
        // you may also want to replace window.fetch here
        window.APIfetch = receiverWindow.fetch;
        // same thing, you may as well replace window.XMLHttpRequest
        window.APIXMLHttpRequest = receiverWindow.XMLHttpRequest;
    }
</script>
<iframe id="receiver" 
        src="http://api.mysite.com/receiver" 
        style="position:absolute;left:-9999px"
        onload="window.setupAPI()"></iframe>
</body></html>

And of course the HTML "http://api.mysite.com/receiver" should retrieve:

<!DOCTYPE html>
<html><body><script>
    document.domain='mysite.com';
</script></body></html>

And then, within your JS code, you can now use APIfetch and APIXMLHttpRequest like you'd use fetch and XMLHttpRequest ... et voilà, no more preflight request whatever the method and content type used!

like image 6
ouk Avatar answered Oct 22 '22 19:10

ouk


Here's an all javascript approach:

document.domain = 'mysite.net';
var apiIframe = document.createElement('iframe');
apiIframe.onload = function(){
    window.XMLHttpRequest = this.contentWindow.XMLHttpRequest;
};
apiIframe.setAttribute('src', API_URL + '/iframe');
apiIframe.style.display = 'none';
document.body.appendChild(apiIframe);

where API_URL + '/iframe' returns this:

<!DOCTYPE html><body><script>document.domain = 'mysite.net'</script></body></html>
like image 2
ricka Avatar answered Oct 22 '22 19:10

ricka