1

This is a Shopify shop pulling images from a public S3 bucket. A javascript function checks via AJAX if the images exist before putting them on an array to be used when rendering the product:

function set_gallery(sku) {

  var bucket = 'https://[xbucket].s3.amazonaws.com/img/sku/';
  var folder = sku.slice(0,4);
  var nombre = sku.replace(' SG OPT ', '');
  var nombre = nombre.replace(' ', '');

  var idx='';
  var ciclo = variant_gallery.attempts;
  var fallos = variant_gallery.failed;

  if (ciclo > 0) { 
    idx = '-'+ciclo; 
  }

  var picURL = bucket+folder+'/'+nombre+idx+'.jpg';

  $.ajax({
    url:picURL,
    type:'GET',
    error: function()
    {
      fallos++;
      ciclo++;
      variant_gallery.failed = fallos;
      variant_gallery.attempts = ciclo;
      if ( fallos < 2 ) { 
        set_gallery(sku); 
      } else {
        variant_gallery.isReady = true;
        build_gallery();
      }
    },
    success: function()
    {
      ciclo++;
      variant_gallery.attempts = ciclo;
      variant_gallery.gallery_urls.push(picURL);
      if ( ciclo < 15 ) { 
        set_gallery(sku); 
      } else {
        variant_gallery.isReady = true;
        build_gallery();
      }
    }
  });
}

This is how the Bucket Policy looks like...

{
    "Version": "2012-10-17",
    "Id": "Policy1600291283718",
    "Statement": [
        {
            "Sid": "Stmt1600291XXXXXX",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::[xbucket]/img/sku/*"
        }
    ]
}

...and CORS Configuration...

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

The problem is that, on Chrome, it renders as expected around 98% of the time (an error every 50 attempts), but in Safari I'm getting a CORS error about once every two or three attempts:

Origin https://shopifystore.com is not allowed by Access-Control-Allow-Origin.
XMLHttpRequest cannot load https://[bucket].s3.amazonaws.com/img/sku/image-to-load.jpg due to access control checks.

What can I do to make it as consistent in Safari as it is from Chrome? Hopefully even more reliable than that.

I have already checked these other SO questions:

AWS S3 bucket: CORS Configuration

AWS S3 CORS Error: Not allowed access

Fix CORS "Response to preflight..." header not present with AWS API gateway and amplify

Chrome is ignoring Access-Control-Allow-Origin header and fails CORS with preflight error when calling AWS Lambda

Intermittent 403 CORS Errors (Access-Control-Allow-Origin) With Cloudfront Using Signed URLs To GET S3 Objects

Cross-origin requests AJAX requests to AWS S3 sometimes result in CORS error

Cached non CORS response conflicts with new CORS request

Some of those won't apply to this scenario. Some others I tried without success.

zJorge
  • 798
  • 2
  • 13
  • 26
  • At the times when you get that CORS error in Safari, what’s the HTTP status code of the response? You can use the Network pane in Safari Web Inspector to check. Is it a 4xx or 5xx error rather than a 200 OK success response? – sideshowbarker Oct 07 '20 at 22:12
  • Thank's @sideshowbarker. Is neither a 2xx or 4xx error. Is actually a 304. Please note that if I directly add the image URL to the src in HTML, either programatically or hardcoded, it will work fine. The problem is that, on the javascript that checks if the image actually exists, sometimes returns success, sometimes "not allowed by Access-Control-Allow-Origin". – zJorge Oct 08 '20 at 01:30

1 Answers1

2

After reading several possible solutions I finally solved with a mix of those. It turns out that this was a cache problem as illustrated here:

Cross-origin requests AJAX requests to AWS S3 sometimes result in CORS error

Cached non CORS response conflicts with new CORS request

I tried that solution first but didn't implemented right with Jquery and I just took another way.

Then tried a few hours later with this solution to avoid cache on jQuery AJAX:

How to prevent a jQuery Ajax request from caching in Internet Explorer?

Finally only added one line of code and got it solved:

  $.ajax({
    url:picURL,
    type:'GET',
    cache: false, // <- do this to avoid CORS on AWS S3
    error: function()
    { 
       ...
    }
zJorge
  • 798
  • 2
  • 13
  • 26