javascriptamazon-web-servicescsvamazon-s3static-html

Upload csv file to S3 bucket from static webpage


I'm trying to create an upload webpage to put csv files in a S3 bucket. I followed the tutorial from their website. https://aws.amazon.com/blogs/compute/uploading-to-amazon-s3-directly-from-a-web-or-mobile-application/

I modified the method to accept parameter filename. Everything works fine but can't find the way to upload file from html to S3.

I'm usual a backend pythonist and google to change this webpage/js, but I didn't manage to solve it.

I tried to change from reader.readAsDataURL(file) to reader.readAsText(file, 'UTF-8'), also data:image/jpg to data:text/csv or text/plain but on line that requires "includes" returns "length: false"

console.log('length: ', e.target.result.includes('data:image/jpeg'))

Down you can find my new code, if you can redirect me to some clues of how can I send csv file and also "?filename=original filename" in API, I'll really love you :).

<!DOCTYPE html>
<html>
<head>
    <title>Upload file to S3</title>
    <script src="https://unpkg.com/vue"></script>
    <script src="https://unpkg.com/axios@0.2.1/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
    <h1>S3 Uploader Test</h1>

    <div v-if="!file">
        <h2>Select a file</h2>
        <input type="file" @change="onFileChange">
    </div>
    <div v-else>
        <img :src="file" />
        <button v-if="!uploadURL" @click="removeFile">Remove file</button>
        <button v-if="!uploadURL" @click="uploadFile">Upload file</button>
    </div>
    <h2 v-if="uploadURL">Success! File uploaded to bucket.</h2>
</div>

<script>
    const MAX_FILE_SIZE = 1000000

    /* ENTER YOUR ENDPOINT HERE */

    const API_ENDPOINT = 'https://<smth>.execute-api.eu-central-1.amazonaws.com/uploads'
    // e.g. https://ab1234ab123.execute-api.us-east-1.amazonaws.com/uploads

    new Vue({
        el: "#app",
        data: {
            file: '',
            uploadURL: ''
        },
        methods: {
            onFileChange (e) {
                let files = e.target.files || e.dataTransfer.files
                if (!files.length) return
                this.createFile(files[0])
            },
            createFile (file) {
                // var image = new Image()
                let reader = new FileReader()
                reader.readAsText(file, 'UTF-8');
                reader.onload = (e) => {
                    //console.log(e.target.result)
                    console.log('length: ', e.target.result.includes('data:/csv'))
                     if (!e.target.result.includes('data:text/csv')) {
                       return alert('Wrong file type', e.target.result)
                    }
                    if (e.target.result.length > MAX_FILE_SIZE) {
                        return alert('File is loo large.')
                    }
                    this.file = e.target.result
                }
                // reader.readAsDataURL(file)
            },
            removeFile: function (e) {
                console.log('Remove clicked')
                this.file = ''
            },
            uploadFile: async function (e) {
                console.log('Upload clicked')
                // Get the presigned URL
                const response = await axios({
                    method: 'GET',
                    url: API_ENDPOINT+'?filename='+'last.csv'
                })
                console.log('Response: ', response)
                console.log('Uploading: ', this.file)
                let binary = atob(this.file.split(',')[1])
                let array = []
                for (var i = 0; i < binary.length; i++) {
                    array.push(binary.charCodeAt(i))
                }
                let blobData = new Blob([new Uint8Array(array)], {type: 'text/csv'})
                console.log('Uploading to: ', response.uploadURL)
                const result = await fetch(response.uploadURL, {
                    method: 'PUT',
                    body: blobData
                })
                console.log('Result: ', result)
                // Final URL for the user doesn't need the query string params
                this.uploadURL = response.uploadURL.split('?')[0]
            }
        }
    })
</script>
<style type="text/css">
    body {
        background: #20262E;
        padding: 20px;
        font-family: sans-serif;
    }
    #app {
        background: #fff;
        border-radius: 4px;
        padding: 20px;
        transition: all 0.2s;
        text-align: center;
    }
    #logo {
        width: 100px;
    }
    h2 {
        font-weight: bold;
        margin-bottom: 15px;
    }
    h1, h2 {
        font-weight: normal;
        margin-bottom: 15px;
    }
    a {
        color: #42b983;
    }
    img {
        width: 30%;
        margin: auto;
        display: block;
        margin-bottom: 10px;
    }
</style>
</body>
</html>


Solution

  • As you are creating a static web site that uses script tags, consider using the AWS SDK for JavaScript to place objects into an Amazon S3 bucket. Uploading objects is covered in the AWS Developer Guide for JavaScript SDK Version 3.

    Uploading photos to Amazon S3 from a browser

    (Of course for your use case, replace photo files with a CSV file).