Caching effect on CORS: No 'Access-Control-Allow-Origin' header is present on the requested resource

廉价感情. 提交于 2019-11-28 03:55:11

https://assets-frontend.kalohq.ink/style.allapps.add899080acbbeed5bb6a7301d234b65.css only returns CORS headers when an "Origin" header is present (which is sent with a CORS request, but not regular requests).

Here's what happens:

  1. User fetches CSS as part of a no-CORS request (eg, <link rel="stylesheet">). This caches due to the Cache-Control header.
  2. User fetches CSS as part of a CORS request. The response comes from the cache.
  3. CORS check fails, no Access-Control-Allow-Origin header.

The server is at fault here, it should use the Vary header to indicate its response changes depending on the Origin header (and others). It sends this header in response to CORS requests, but it should send it in response to non-CORS requests too.

Chrome is somewhat at fault here, as it should use the credentials mode of the request as part of the caching key, so a non-credentialed request (such as those sent by fetch()) shouldn't match items in the cache that were requested with credentials. I think there are other browsers that behave like Chrome here, but Firefox doesn't.

However, since you're using a CDN, you can't rely on browsers to get this right, as the caching may still happen at the CDN. Adding the correct Vary header is the right fix.

tl;dr: Add the following header to all of your responses that support CORS:

Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method

We experienced the same problem when migrating our JS to Webpack.

Our setup is similar:

  • assets are uploaded to an S3 bucket during deployment
  • the bucket is set as the Cloudfront origin

When migrating to Webpack, we wanted to take advantage of JS sourcemaps for better error reporting to Airbrake. To allow errors to be catched properly, the crossorigin="anonymous" attribute had to be set on the script tags. The reason why is explained here: https://blog.sentry.io/2016/05/17/what-is-script-error.html

Part of the problem was that CORS response headers were sometimes returned, sometimes not, triggering a CORS errror in the browser. Cloudfront servers were caching the response with OR without the CORS headers, depending on the first client request making a Miss request.

So two possible outcomes:

  1. First client does not send the Origin request header => Cloudfront server caches the response without CORS headers.
  2. First client sends the Origin request header => Cloudfront server caches the response without CORS headers.

This made the problem look like it was random, but it was just a matter of race condition (how the first client made the request) and different headers cached on different Cloudfront servers: timing and location dependent. Add to that the fact that browsers might cache these wrong headers...

So you need to properly configure Cloudront's distribution behavior to:

  • allow and cache preflight (OPTIONS) requests
  • base the cache on CORS request headers (Origin, Access-Control-Request-Headers, Access-Control-Request-Method)

Here is the configuration that solved our problem.

S3 bucket / Permissions / CORS configuration:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <MaxAgeSeconds>300</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Cloudfront distribution / Edit Behavior:


We now experience a problem similar to yours, as we just migrated our CSS to Webpack. We are experiencing even more sporadic CORS errors for CSS files. We are trying to remove the crossorigin="anonymous" attribute on <link rel="stylesheet" /> tags since we don't need error tracking for CSS files.

I can shed a little light to how it happened with us. Azure CDN (which we use) does not support Vary: headers right now. So far so bad. But now we use the script crossorigin attribute which - and thats the interesting thing - is not supported by some browsers.

If now such browser comes to our site, it does not send origin: because it does not understand the "crossorigin" attribute. If later another one comes who understands it, it will send origin: -> CORS Error because first response is cached.

Ugly.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!