I am trying to write an nginx config that will handle two sites on both http and https, it seems to work as long as a client never visits both sites, but if they do there are caching/cross-site issues.
# Allow cross origin
location ~* \.(eot|svg|ttf|woff|woff2|json)$ {
if ($http_origin ~* (https?://(admin\.)?example\.com(:[0-9]+)?)) {
add_header 'Access-Control-Allow-Origin' "$http_origin";
}
}
So if I load example.com, everything works, but then when I load admin.example.com I get issues like this
(index):1 XMLHttpRequest cannot load http://origin.example.com/js/data-lib/currency.json. The 'Access-Control-Allow-Origin' header has a value 'http:// example . com' that is not equal to the supplied origin. Origin 'http:// admin . example . com' is therefore not allowed access.
As near as I can tell this is because the browser cached the original request with the header it came with, and now it's denying me even though another request from the server would allow it. The proof is if I check the Disable Cache in the Chrome Developer tools then the issue never happens.
How do I solve this issue? Is it possible to do multiple domains + ssl/http all in one config, or is it necessary to split this up based on the domain and protocol being requested?
(Sorry about the horrible spaces in my example, apparently StackOverflow thinks I'm trying to post links when I'm just writing examples)
If you add the Vary
response header with the value Origin
, that should have the effect of causing any browser to skip its cache and make a new network request when the value of the Origin
request header is different from the Origin
value of the request it cached from.
See the relevant part of the HTTP spec. So you could update your nginx config to do this:
# Allow cross origin
location ~* \.(eot|svg|ttf|woff|woff2|json)$ {
if ($http_origin ~* (https?://(admin\.)?example\.com(:[0-9]+)?)) {
add_header 'Access-Control-Allow-Origin' "$http_origin";
}
add_header 'Vary' "Origin";
}
You can read up more in the MDN article on the Vary
response header.
The
Vary
HTTP response header determines how to match future request headers to decide whether a cached response can be used rather than requesting a fresh one from the origin server. It is used by the server to indicate which headers it used when selecting a representation of a resource in a content negotiation algorithm.
…and in the MDN Access-Control-Allow-Origin
article’s CORS and caching section:
If the server sends a response with an
Access-Control-Allow-Origin
value that is an explicit origin (rather than the "*
" wildcard), then the response should also include aVary
response header with the valueOrigin
— to indicate to browsers that server responses can differ based on the value of theOrigin
request header.
…and in the Fetch spec itself:
If your requirements are more complicated than setting
Access-Control-Allow-Origin
to*
or a static origin, use theVary: Origin
response header.If
Vary
is not used and a server is configured to sendAccess-Control-Allow-Origin
for a certain resource only in response to a CORS request: When a user agent receives a response to a non-CORS request for that resource, the response will lackAccess-Control-Allow-Origin
and the user agent will cache that response. If the user agent then encounters a CORS request for the resource, it will use that cached response from the previous non-CORS request — withoutAccess-Control-Allow-Origin
.But if
Vary: Origin
is used in the same scenario, it will cause the user agent to fetch a response that includesAccess-Control-Allow-Origin
, rather than using the cached response from the previous non-CORS request lackingAccess-Control-Allow-Origin
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