Smlok
Smlok

Reputation: 658

S3 creating empty files when uploading a file from React contact form using Axios

I have created a test contact form where a user can upload an image attachment.

However, in S3 all files appear empty. The size seems to change depending on the length of the link size (e.g. blob is 63B, a hard-coded link varies in size), so it seems like it just takes the link as data, not the actual image. I checked many times if my axios syntax is correct and went through numerous threads here in SO but can't figure out what am I doing wrong.

AWS Lambda to generate the presigned URL:

const AWS = require('aws-sdk')
AWS.config.update({ region: 'eu-west-2' })
const s3 = new AWS.S3();

const uploadBucket = 'xxx-bucket'

exports.handler = async (event) => {
  const result = await getUploadURL()
  console.log('Result: ', result)
  return result
};

const getUploadURL = async function() {
  console.log('getUploadURL started')
  let actionId = Date.now()

  var s3Params = {
    Bucket: uploadBucket,
    Key:  `${actionId}.jpg`,
    ContentType: 'image/jpeg',
    CacheControl: 'max-age=31104000',
    ACL: 'public-read'
  };

  return new Promise((resolve, reject) => {
    // Get signed URL
    let uploadURL = s3.getSignedUrl('putObject', s3Params)
    resolve({
      "statusCode": 200,
      "isBase64Encoded": false,
      "headers": {
        "Access-Control-Allow-Origin": "*"
      },
      "body": JSON.stringify({
          "uploadURL": uploadURL,
          "photoFilename": `${actionId}.jpg`
      })
    })
  })
}

React Frontend:

class QuoteForm extends Component {

  constructor(props) {
    super(props);
    this.state = {
      file:null,
    };
  };

  onContactNameChange(e){
    this.setState({ContactName:e.target.value});
  };

  onFileChange(e){
    let [file] = e.target.files;
    if (file) {
      this.setState({
        file: URL.createObjectURL(e.target.files[0]),
      });
      console.log(file);
    }
  };

  async handleSubmit(e){
    e.preventDefault();
  
      axios.post(`https://xxxx/`)
      .then(res => {
            console.log(res)
            const url = res.data.uploadURL;

            const axiosConfig = {
                headers: { 
                    "Content-Type": "image/jpeg",
                    "Cache-Control": 'max-age=31104000' 
                }
            }

            axios.put(url, this.state.file, axiosConfig)
                .then(response => {console.log(response)}).catch(err => {console.log(err.response)
            });
        });

    }
  
  render() {
    return (
      <form onSubmit={this.handleSubmit.bind(this)}>
            <input 
                type="file"
                name="file"
                id="fileUpload" 
                onChange={this.onFileChange.bind(this)}
            />

            <img src={this.state.file} alt="img" />

            <button 
                className="large"
                style={{marginTop:"1.25rem"}} >
                Submit
            </button>
      </form>
    );
  }
}

S3 Bucket files: enter image description here

I just can't understand why the files in S3 bucket turn up empty.

Upvotes: 2

Views: 1789

Answers (1)

Smlok
Smlok

Reputation: 658

Ok, I figured out what was my issue. createObjectURL in my frontend React code apparently can't be used to upload files to server since it doesn't actually include the file, but the URL only. I shortened the whole onFileChange(e) function to the one below and S3 started receiving the actual files.

  onFileChange(e){
        const [selectedFile] = e.target.files;
    if (selectedFile) {
            this.setState({file:selectedFile})
        }
  };

Upvotes: 1

Related Questions