Five Simple Steps to Upload file directly to S3 in Reactjs

s3_video_thumbFor Direct file uploading to s3 using  React, you need to do following 5 steps,

  1. We will update CORS configuration for AWS S3.
  2. Generate policy and signature.
  3. Retrieve policy and signature using ajax call. 
  4. upload file using React form
  5. Ajax Request For Direct File Upload to s3

1. AWS S3 Setup:

Sign in to the AWS console and select the S3 section. Select or create bucket and click the ‘Properties’ tab. Select the Permissions section and three options are provided (Add more permissions, Edit bucket policy and Edit CORS configuration).

cors

CORS (Cross-Origin Resource Sharing) will allow your application to access content in the S3 bucket. Each rule should specify a set of domains from which access to the bucket is granted and also the methods and headers permitted from those domains.

I have used following CORS configuration for my application:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
   <CORSRule>
        <AllowedOrigin>http://example.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

For more details: https://devcenter.heroku.com/articles/s3-upload-python

2. Policy and Signature:

I am using Rails app to generate policy and signature. You can use any app to do same thing. Add following helper methods

def signature
    policy = policy({ secret_access_key: ENV['SECRET_ACCESS_KEY']})
    signature = Base64.encode64(
        OpenSSL::HMAC.digest(
            OpenSSL::Digest::Digest.new("sha1"),
            ENV['SECRET_ACCESS_KEY'],
            policy
        )
    ).gsub(/\n/, "")
end
def policy(options = {})
    Base64.encode64({
        expiration: 24.hours.from_now.utc.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
        conditions: [
            { bucket: ENV['BUCKET'] },
            { acl: "public-read" },
            ["starts-with", "$key", ""],
            ["starts-with", "$Content-Type", ""] 
        ]
  }.to_json).gsub(/\n|\r/, "")
end

def aws_key_id
    ENV['AWS_ACCESS_KEY_ID']
end

Set SECRET_ACCESS_KEY, BUCKET, AWS_ACCESS_KEY_ID and BUCKET in your environment variables. You can also set it as rails variable but setting environment variables is more secured method.

3.API call to Retrieve Signature and Policy

componentWillMount: function() {
    $.ajax({
    method: 'GET',
    url: "https://example.com/your_url"
    }).done(function(data) {this.setState({data: data})}.bind(this))
 }

Retrieve aws_key_id, signature, policy  using AJAX call in componentWillMount method of React so that  aws_key_id, policy, signature will be available in states before component gets mounted and can be retrieved using {this.state.policy},{this.state.signature},{this.state.aws_key_id} .

4.Define React Component

your component’s  render function which take file as input,

render: function(){
  return(

) }

5.Finally Ajax Request For Direct File Upload to s3

Here is the ajax request,

First you need to define your form data,

(more details about form data visit : https://aws.amazon.com/articles/1434)

submit: function(){
     var data = new FormData();
     data.append("key",your_folder/${filename})
     data.append("AWSAccessKeyId",Your_aws_key_id)
     data.append("acl","private")
     data.append("policy",Your_policy_document_base64_encoded)
     data.append("signature",Your_calculated_signature)
     data.append("Content-Type",Your_file_type)
     data.append("file",file)

     $.ajax({
       url : "http://your_bucket_name.s3.amazonaws.com",
       type: 'POST',
       data: data,
       contentType: false,
       processData: false,
       success: function(){
         //do something
      },
      error: function(){
         //do something
      }
    })
 }

That’s it , Happy Coding 🙂

 

 

 

 

 

 

 

Leave a comment