Reputation: 7153
I'm trying to upload to GCP from the frontend with fetch, using a signed URL and I'm running into persistent CORS issue.
Is the file to be uploaded supposed to be embedded in the signedurl, or sent to the signedurl in a request body?
This is the error:
Access to fetch at <signedurl> from origin 'http://my.domain.com:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
This is the CORS config on the bucket:
[
{
"origin": ["http://gcs.wuddit.com:3000"],
"responseHeader": ["Content-Type", "Authorization", "Content-Length", "User-Agent", "x-goog-resumable", "Access-Control-Allow-Origin"],
"method": ["GET", "POST", "PUT", "DELETE"],
"maxAgeSeconds": 3600
}
]
This is the fetch call:
const uploadHandler = async (theFile, signedUrl) => {
try {
const response = await fetch(signedUrl, {
method: 'POST',
headers: {
'Content-Type': theFile.type,
},
body: theFile,
});
const data = await response;
} catch (error) {
console.error('Upload Error:', error);
}
};
Signed URL example:
// https://storage.googleapis.com/my-bucket-name/my-filename.jpg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=wuddit-images-service%40wuddit-427.iam.gserviceaccount.com%2F20210305%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20210305T032415Z&X-Goog-Expires=901&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature=18a2428f051e59fbeba0a8b97a824bdee0c70cffe1f9cce5696e95b9fd81b74974f1c291e5195e874eac29ede5619c9cf07538f21b442fb81e7fc1e764bb5444f5d7acae78e3f2b5876450fccde122f059348efc6d5d8be1bbef7250a1aa2433957d85e65f51c69e8daf020341cbf8044ed2b532205a331acc3728437c9295b25bb6e61ef71a99798bb38a6f05e664678d5e12aed916ab41d2e2f9e7e0974588b797ebef87f2c0949f7071687d1d12f232e871d892f6cd2da397888285783d5372657822275f56a44f9ca14a21fb4e4d6552d380f9e4a597d12663c51aea0a2bdc0f47994f687b59c9d629c1010245cefc975718f3574cd6ae331aa1b89d797d
Upvotes: 11
Views: 11332
Reputation: 7153
I figured this out. My lord. In my node Express backend, on the endpoint I was using to call the generateV4UploadSignedUrl()
function, I had to set
the Access-Control-Allow-Origin
on the res
.
So this:
app.get('/api/gcloud', async (req, res) => {
try {
const url = await generateV4UploadSignedUrl().catch(console.error);
res.json({ url });
} catch (err) {
console.log('err', err);
}
});
Became this:
app.get('/api/gcloud', async (req, res) => {
res.set('Access-Control-Allow-Origin', 'http://gcs.whatever.com:3000'); // magic line. Note this must match the domain on your GCP bucket config.
try {
const url = await generateV4UploadSignedUrl().catch(console.error);
res.json({ url });
} catch (err) {
console.log('err', err);
}
});
My bucket CORS config:
[
{
"origin": "http://gcs.whatever.com:3000",
"responseHeader": ["Content-Type", "Authorization"],
"method": ["GET", "POST", "PUT", "DELETE"],
"maxAgeSeconds": 3600
}
]
Save the above into a file, e.g. 'cors.json', then cd into the location where you saved the file, then use this gsutil command to set bucket CORS config:
gsutil cors set cors.json gs://your-bucket-name
Upvotes: 10
Reputation: 61
[
{
"origin": ["*"],
"method": ["*"],
"maxAgeSeconds": 3600,
"responseHeader": ["*"]
}
]
worked for me. responseHeader was the missing ingredient!
Upvotes: 6