CORS-less Cross-Origin Requests

Indrek Juhkam
Feb 18 · 6 min read

CORS, you so slow!

Use caching?

CORS caching is very restrictive:

  • Many RESTful URLs include some kind of resource ID in the URL. Caching DELETE /articles/1 still means that the browser has to do a new preflight request when invoking DELETE /articles/2.

Send only simple requests?

CORS specification says that preflight requests are not mandatory for Simple Requests. A request is considered simple if it follows these rules:

  • Only Accept, Accept-Language, Content-Language and Content-Type headers are used.
  • Content-Type header is set to application/x-www-form-urlencoded, multipart/form-data or text/plain

Avoiding CORS Requests

As usual in the world of web development, there are ways to work around the restrictions imposed by browsers.


This solution works only when both the site and the server share the same base domain. Lets say you have a public API on and a user-facing site (the APP) on Making a request from the APP to the API will trigger a preflight request because the subdomains are different.

<!-- -->
     document.domain = '';
     window.parent.fetch = window.fetch.bind(window);
  1. We override the parent window fetch function with the current window fetch function.
<script>document.domain = ‘’</script>
<iframe src=”"></iframe>
  • Cacheable. The proxy HTML doesn’t need to change except when we want to change the domain which should be a very rare occurrence. We can serve it from the API server with a long cache or even upload it to a CDN.
  • Low effort. All it entails is exposing one static page and adding two lines of code to the user-facing site.
  • Includes an iframe
  • This works only with one API domain. Overwriting fetch is not an option when having more than one API domain. We can however expose them as different fetch functions (e.g. window.api1Fetch and window.api2Fetch).


postMessage approach uses iframes like document.domain solution but it allows having sites on completely different domains.

  • Needs a custom adapter for making requests. With document.domain method we were able to continue to use the Fetch API exactly as before. Here we need a custom adapter to facilitate the communication between the frames and ensure everything works even if loading the iframe fails.

Reverse Proxy

This solution works by exposing the API on the current domain. E.g. If you have API served on and your APP is on then you can set up a reverse proxy on that proxies all requests to

  • Supports different domains. It doesn’t matter where the API is located. The entire domain can be different.
  • Cannot be used when the user-facing site is not owned by us. E.g. in Glia we provide a JavaScript API to our clients. It’s not reasonable to force each of our clients to set up a reverse proxy like just so that we could avoid cross domain requests from our JS API.
  • It changes the URLs which may be annoying.

WebSocket Proxy

This is the most complex solution. It can be a useful approach when other approaches are not possible or when users are already connected to an existing WebSocket server.

  • Supports different domains.
  • Complex. Needs a server which knows how to translate WebSocket messages to HTTP requests.
  • Security concerns. All proxied requests are now using the WebSocket Proxy server IP. This can end up badly when the WebSocket Proxy server does not whitelist allowed domains, do rate-limiting, etc.


CORS can have a high performance impact for sites that do a lot of cross-origin requests. Browsers have features like CORS caching, but these are not very efficient. The best option is to avoid preflight requests altogether whenever possible.

Glia Tech

Glia engineering and technology blog

Indrek Juhkam

Written by

Glia Tech

Glia Tech

Glia engineering and technology blog