Corrupted image on uploading image to AWS-S3 via signed url

Viewed 3057

I'm trying to upload images to aws-s3 via a signed-url from NodeJS server (not from a browser). The image to upload has been generated by NodeJS. I'm getting the signed-url from aws and succeeding to upload it to s3.

But my image is corrupted. For some reason, S3 is adding some headers to my image (compare image attached).

What am I doing wrong?

getting the signed url:

    try {
        var params = {
            Bucket: bucketName,
            Key: 'FILE_NAME.png',
            Expires: 60
        };
        const url = await s3.getSignedUrlPromise('putObject', params);
        return url;
    } catch (err) {
        throw err;
    }

uploading to s3

        var stats = fs.statSync(filePath);
        var fileSizeInBytes = stats["size"];
        const imageBuffer = fs.readFileSync(filePath);

        var formData = {
            'file': {
                value: imageBuffer,
                options: {
                    filename: 'FILE_NAME.png'
                }
            }
        };

        request({ 
            method: 'put',
            url, 
            headers: {
                'Content-Length': fileSizeInBytes,
                'Content-MD': md5(imageBuffer)           
            }, 
            formData 
        }, function (err, res, body) {
             console.log('body',body);
        });

Compare between the actual image and the uploaded image to s3. S3 added some headers:

compare

3 Answers

I know this is old but I struggled with the same issue for a while. When uploading using a pre-sgined url, DO NOT use new FormData();

One thing I noticed that all of my files on s3 were exactly 2kb larger than the originals.

<input type="file" id="upload"/>

var upload = document.getElementById('upload');
var file = upload.files[0];

//COMMENTED OUT BECAUSE IT WAS CAUSING THE ISSUE
//const formData = new FormData();
//formData.append("file", file);

// Assuming axios

const config = {
    onUploadProgress: function(progressEvent) {
        var percentCompleted = Math.round(
            (progressEvent.loaded * 100) / progressEvent.total
        );
        console.log(percentCompleted);
    },
    header: {
        'Content-Type': file.type
    }
};

axios.put(S3SignedPutURL, file, config)
   .then(async res => {
        callback({res, key})
    })
    .catch(err => {
        console.log(err);
    })

I followed the above solution for react js

What I was doing before uploading an image is passing through the createObject URL and then passing it to the API body.

if (e.target.files && e.target.files[0]) {
            let img = e.target.files[0];
            **setImage(URL.createObjectURL(img))**

Correct Way:

if (e.target.files && e.target.files[0]) {
            let img = e.target.files[0];
            **setImage(img)**

Work For me, Thanks Sam Munroe

Try to specify the content type in the request as Content-Type multipart/form-data.

Related