问题
I'm using a React web app and trying to upload a file to AWS S3.
I've tried everything both locally (localhost:3000
) and when deployed to production (Vercel serverless functions).
I first use a fetch to retrieve a presigned url for the file upload, which works perfectly:
module.exports = async (req, res) => {
let {fileName, fileType} = req.body;
const post = await s3.createPresignedPost({
Bucket: BUCKET_NAME,
Fields: {
key: fileName
},
ContentType: fileType,
Expires: 60
});
res.status(200).json(post);
Then, in the second fetch:
await fetch(url, {method: 'POST', body: formData}
I'm getting:
fetch has been blocked by CORS policy: No 'Access-Control-Allow-Origin'
I have set up the Permissions -> CORS json in the bucket configuration correctly:
[
{
"AllowedHeaders": [
"*",
"Content-*"
],
"AllowedMethods": [
"HEAD",
"GET",
"PUT",
"POST",
"DELETE"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"*"
]
}
]
I also verified the bucket name in my code.
I've tried:
- Both
getPresignedUrl
&createPresignedPost
to generate the url - Both
PUT
&POST
requests - Setting headers (
Content-Type
,x-amz-acl
) in the fetch request - Using different CORS jsons, allowing all origins, expose different headers, allowing all methods (including
HEAD
, allowing different headers (like"Content-*"
) - Configuring different users with different permissions (specifically what I need, all S3 permissions, etc)
- Settings bucket policy
- Clearing Chrome's cache (using Hard Reload) or by code before every try
I've tried everything and went over dozens of articles (1, 2) and browsing through questions here - but it's still not working. Not locally and not in production.
回答1:
Make sure the file name match exactly with Key
const bucketParms = {
Bucket: "sample-temp-bucket",
Key: "HeadShot.jpg",
Expires: 3600,
};
s3.getSignedUrl("putObject", bucketParms, (error, url) => {
if (error) console.log("error", error);
if (url) console.log("url", url);
});
Right here we can test the url generated from postman or curl
Then we can make a http PUT
call.
this.http
.put(
"https://sample-temp-bucket.s3.amazonaws.com/HeadShot.jpg?X-Amz-Algorithm=AWS4-HMAC....",
formData
)
.subscribe((response) => {
console.log("response received is ", response);
});
and the CORS, wild card for ExposeHeaders
is not accepting(at least from console), it worked with just empty array "ExposeHeaders": []
回答2:
After endless hours of digging into this, I found the issue.
The reason for the CORS error was that I didn't include the region
in the initial AWS.config.update
configuration setup.
Once I added the region
key, the CORS error was solved:
const AWS = require('aws-sdk');
AWS.config.update({
accessKeyId: 'XXXXX',
secretAccessKey: 'XXXXXX',
region: 'us-west-2', // Must be the same as your bucket
});
const s3Client = new AWS.S3();
It's really confusing and misleading that the error returned for not configuring the bucket region is CORS.
来源:https://stackoverflow.com/questions/65963830/uploading-formdata-file-from-client-to-s3-using-createpresignedpost-or-getpresig