I am using node.js to upload image to my s3 bucket on my local environment using localstack

here is my API code:

const s3 = new AWS.S3({
  accessKeyId: 'testKEYId',
  secretAccessKey: 'testSecret',
  region: 'ap-south-1',
  sslEnabled: false,
  endpoint: 'http://localhost:4566',
});

app.post('/upload-1', upload.any(), (req, res) => {
  const imagePath = './myfolder/my-image.jpg'; // Update with your image file path
  const bucketName = 'my-buckert'; // Update with your S3 bucket name
  const remoteFileName = 'uploaded_image.jpg';

  const fileContent = fs.readFileSync(imagePath);

  console.log(fileContent);

  const params = {
    Bucket: bucketName,
    Key: remoteFileName,
    Body: fileContent,
  };

  const bucketParams = {
    Bucket: bucketName,
  }

  s3.upload(params, (err, data) => {
    if (err) {
      console.error('Error uploading image to S3:', err);
    } else {
      console.log('Image uploaded successfully. S3 location:', data.Location);
    }
  });
});

when i am calling this API then i am getting this error:

exception during call chain: Unable to parse request (not well-formed (invalid token): line 1, column 0), invalid XML received:

Refer screenshot: enter image description here

2

There are 2 answers

1
bentsku On BEST ANSWER

This issue stems from using Virtual-Hosted style requests against LocalStack when using localhost as the endpoint.

Your SDK is prepending the bucket to your host which leads to a request looking like this:
http://my-buckert.localhost:4566/uploaded_image.jpg
LocalStack is not able to parse the bucket name from your host if the bucket name is is not followed by .s3., and will treat this request as a CreateBucket call.

There are two solutions to this, outlined in the documentation here: https://docs.localstack.cloud/user-guide/aws/s3/#path-style-and-virtual-hosted-style-requests

In your case, the simplest would be to use s3ForcePathStyle for your client. Creating your client this way should fix your issue:

const s3 = new AWS.S3({
  accessKeyId: 'test',  // I would advise to use `test` and `test` for the keys
  secretAccessKey: 'test',
  region: 'ap-south-1',
  sslEnabled: false,
  endpoint: 'http://localhost:4566',
  s3ForcePathStyle: true,
});

More about the configuration of the javascript AWS SDK here: https://docs.localstack.cloud/user-guide/integrations/sdks/javascript/

0
user2628783 On

I was facing the same issue, the reason mentioned by @bentsku is correct. After I have enabled pathStyleAccess it all worked for me :).

Here is my S3 Client creation code

   private static AmazonS3 getLocalS3() {
    BasicSessionCredentials awsCreds = new BasicSessionCredentials("test", "test", "");
    return AmazonS3ClientBuilder.standard()
            .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
            .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("http://localhost:4566", "us-east-2"))
            .enablePathStyleAccess()
            .build();
}

Many thanks to @bentsku