从静态网页上传 csv 文件到 S3 存储桶

Posted

技术标签:

【中文标题】从静态网页上传 csv 文件到 S3 存储桶【英文标题】:Upload csv file to S3 bucket from static webpage 【发布时间】:2021-10-14 19:15:13 【问题描述】:

我正在尝试创建一个上传网页以将 csv 文件放入 S3 存储桶中。 我按照他们网站上的教程进行操作。 https://aws.amazon.com/blogs/compute/uploading-to-amazon-s3-directly-from-a-web-or-mobile-application/

我修改了接受参数文件名的方法。一切正常,但找不到将文件从 html 上传到 S3 的方法。

我通常是后端 pythonist 和 google 来更改此网页/js,但我没有设法解决它。

我尝试从 reader.readAsDataURL(file) 更改为 reader.readAsText(file, 'UTF-8'),还将 data:image/jpg 更改为 data:text/csv 或 text/plain 但在线需要“包括”返回“长度:假”

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

您可以在下面找到我的新代码,如果您可以将我重定向到一些关于如何发送 csv 文件以及 API 中的“?文件名=原始文件名”的线索,我真的很爱你 :)。

<!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>

【问题讨论】:

【参考方案1】:

感谢@smac2020 的指导,仍然很有用,我没有机会进一步研究它。 经过几个小时的 vue.js 学习,制作了这个工作代码。

<!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>
        <div>File  name  loaded </div>
        <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: '',
            name: ''
        ,
        methods: 
            onFileChange (e) 
                let files = e.target.files || e.dataTransfer.files
                if (!files.length) return
                this.createFile(files[0])
            ,
            createFile (file) 
                let reader = new FileReader()
                this.name = file.name
                console.log(this.name)
                reader.readAsText(file, 'UTF-8');
                reader.onload = (e) => 
                    if (e.target.result.length > MAX_FILE_SIZE) 
                        return alert('File is loo large.')
                    
                    this.file = e.target.result
                
            ,
            removeFile: function (e) 
                console.log('Remove clicked')
                this.file = ''
            ,
            uploadFile: async function (e) 
                console.log('Upload clicked', this.name)
                // Get the presigned URL
                const response = await axios(
                    method: 'GET',
                    url: API_ENDPOINT+'?filename='+this.name
                )
                console.log('Response: ', response)
                let blobData = new Blob([this.file], 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>

【讨论】:

【参考方案2】:

在创建使用脚本标签的静态网站时,请考虑使用 AWS SDK for JavaScript 将对象放入 Amazon S3 存储桶中。 适用于 javascript 开发工具包版本 3 的 AWS 开发人员指南中介绍了上传对象。

Uploading photos to Amazon S3 from a browser

(当然对于您的用例,将照片文件替换为 CSV 文件)。

【讨论】:

感谢重定向。几个小时后 :) 学习了更多 Vue.JS 并解决了我的问题。 > 完全放弃 '''"result.includes('"'''' - 我想是与图像文件有关的东西。 > 在 vue.js 变量定义中创建一个变量并从 file.name 中获取名称 > 和 blobData我定义为 '''let blobData = new Blob([this.file], type: 'text/csv')'''

以上是关于从静态网页上传 csv 文件到 S3 存储桶的主要内容,如果未能解决你的问题,请参考以下文章

将静态文件上传到 aws s3 存储桶后,css 中的 URL 不起作用

直接从服务器将 csv 文件上传到 aws s3 存储桶

我可以从不同的 S3 存储桶提供静态网站的一部分吗?

使用 lambda 函数通过 s3 存储桶将巨大的 .csv 文件上传到 dynamodb 时出错

如何从 S3 存储桶中读取最后修改的 csv 文件?

将文件从私有 S3 存储桶读取到 pandas 数据帧