Uploading formData file from client to S3 using createPresignedPost or getPresignedUrl fails due to CORS

跟風遠走 提交于 2021-02-05 09:24:26

问题


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

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