user3352975
user3352975

Reputation: 302

Why is Google Cloud Storage always answering with cors error: No 'Access-Control-Allow-Origin' header is present on the requested resource

I'm trying to upload files to Google Cloud Storage (GCS) from the client browser. For that I have a back-end in node.js request a Signed URL from GCS, which is then transmitted to the front-end client to upload the file. The Signed URL request code is the following:

const options = {
    version: "v4",
    action: "write",
    expires: Date.now() + 15 * 60 * 1000, // 15 minutes
    contentType: content_type,
  };

  // Get a v4 signed URL for uploading file
  const [url] = await storage
    .bucket(bucketName)
    .file(filename)
    .getSignedUrl(options)

This is working. The issue comes when I try using the Signed URL on the client. Every request ends up with the following error:

Access to XMLHttpRequest at 'https://storage.googleapis.com/deploynets_models/keras_logo.png?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=urlsigner%40deploynets.iam.gserviceaccount.com%2F20200711%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20200711T192805Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature=82b73435e4759e577e9d3b8056c7c69167fdaac5f0f450381ac616034b4830a7661bdb0951a82bf749a35dc1cf9a8493b761f8993127d53948551d7b33f552d118666dcf8f67f494cfaabf2268d7235e955e1243ce3cd453dcc32552677168ad94c6f1fca0032eb57941a806cc14139915e3cd3efc3585497715a8ad32a1ea0278f2e1165272951ae0733d5c6f77cc427fd7ff69431f74f1f3f0e7779c28c2437d323e13a2c6474283b264ab6dc6a94830b2b26fde8160684839a0c6ea551ca7eff8e2d348e09a8c213a93c0532f6fed1dd167cd9cf3480415c0c35987b27abd03684e088682eb5e89008d33dcbf630b58ea6b86e7d7f6574466aa2daa982566' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I've set the CORS policy on the GCS bucket with the following JSON:

[
  {
    "origin": ["*"],
    "method": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    "responseHeader": ["*"],
    "maxAgeSeconds": 120
  }
]

(I've also tried listing specifically the origin as http://localhost:3000 for example)

It should be mentioned that I have got it to work in one specific case: when the upload payload is just a plain string. For some reason it works fine then.

I've looked up online all the similar errors I could but to no avail so far. Any idea?

Upvotes: 3

Views: 4453

Answers (3)

Aditya Pol
Aditya Pol

Reputation: 33

I was facing the exact same issue and there was a problem with the options that I was passing, try changing the options to

const options = {
    action: "write",
    expires: Date.now() + 15 * 60 * 1000, // 15 minutes
  }

this solution worked for me.

Upvotes: 0

Khaled
Khaled

Reputation: 927

Update: Finally got it to work! I had to add contentType: 'application/octet-stream', and processData: false, for it to work. Otherwise I was getting the errors:

  1. CORS error Access to fetch at 'https://storage.googleapis.com/...' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
  2. Uncaught TypeError: Illegal invocation and Uncaught (in promise) TypeError: Failed to execute 'arrayBuffer' on 'Blob': Illegal invocation

So final AJAX request looks like this (working):

$.ajax({
  url: <GCS signed upload URL>,
  type: 'PUT',
  data: f, //file object
  contentType: 'application/octet-stream', //seems to be required
  processData: false, //seems to be required
})

I also had to set the bucket CORS using the command:

gsutil cors set gcs_cors.json gs://<my_bucket>

The file gcs_cors.json contents were:

[
  {
    "origin": ["https://<myapp>.appspot.com", http://localhost:8080"],
    "responseHeader": ["Content-Type"],
    "method": ["GET", "HEAD", "DELETE", "PUT", "POST"],
    "maxAgeSeconds": 120
  }
]

Original post: I am not sure how this worked for you (happy it did though!), I have tried using the file directly and using Form Data but it was not working. Uploading to GCS seems to be quite a frustrating process. I was hoping the documentation would have a complete working example (front-end/back-end) but it doesn't seem to be the case.

Upvotes: 1

user3352975
user3352975

Reputation: 302

I figured out what was wrong. In the upload code (browser side), I was passing a FormData object as the data to be uploaded, which for some reason was triggering the CORS error above. I fixed it when I passed the file directly.

So instead of using the following:

var data = new FormData()
data.append('file', event.target.files[0])

I use directly the file in event.target.files[0].

Upvotes: 0

Related Questions