I am building a REST application that makes use of CORS. Every REST call is different and I am finding that there is significant overhead in getting the preflight OPTIONS call. Is there a way to cache and apply a preflight OPTIONS result so that any subsequent calls to the same domain use the cached response?
Preflight Caching Using Browser The concept behind this is straightforward. Preflight cache behaves similarly to any other caching mechanism. Whenever the browser makes a Preflight request, it first checks in the Preflight cache to see if there is a response to that request.
A CORS preflight OPTIONS request can be triggered just by adding a Content-Type header to a request — if the value's anything except application/x-www-form-urlencoded , text/plain , or multipart/form-data .
CORS caching for CDNsThis caches the response in public caches (e.g. CDNs) for 24 hours, which should be enough for most cases without risking cache invalidation becoming a problem. For initial testing, you might want to set the cache time shorter, and increase it once you're happy that everything is set up correctly.
CORS also relies on a mechanism by which browsers make a "preflight" request to the server hosting the cross-origin resource, in order to check that the server will permit the actual request. In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request.
Preflight can only be applied to the request, not to the entire domain. I brought the same question up on the mailing list, and there were security concerns. Here's the entire thread: http://lists.w3.org/Archives/Public/public-webapps/2012AprJun/0228.html
There are a few things to consider if you'd like to limit the number of preflight requests. First note that WebKit/Blink based browsers set a max preflight cache of 10 minutes:
https://github.com/WebKit/webkit/blob/master/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp https://chromium.googlesource.com/chromium/blink/+/master/Source/core/loader/CrossOriginPreflightResultCache.cpp
(I'm not sure if this is true for other browsers). So while you should always set the Access-Control-Max-Age header, the max value is 10 minutes.
Next note that it is impossible to avoid a preflight on PUT/DELETE requests. So updates/deletes to your API will require at least one preflight every 10 minutes.
On GET/POST, avoid custom headers if at all possible, since these still trigger preflights. If your API returns JSON, note that a Content-Type of 'application/json' also triggers a preflight.
If you are willing to bend just how "RESTful" your API is, there are a few more things you can try. One is to use a Content-Type that doesn't need a preflight, like 'text/plain'. Custom headers always trigger preflights, so if you have any custom headers, you could move them into query parameters. At the extreme end, you could use a protocol like JSON-RPC, where all requests are made to a single endpoint.
In all honesty, because of the browser's preflight cache limit of 10 minutes, and REST's resource urls, the preflight cache is fairly useless. There's very little you can do to limit preflights over the course of a long running app. I'm hopeful the authors of the CORS spec will try to address this in the future.
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