使用预签名 POST url 将文件上传到 AWS S3 时设置随机文件名

Set random file name when upload file to AWS S3 with pre-signed POST url

我使用签名 POST url 和 jQuery-file-upload 直接将图像上传到 AWS S3。

它在我的电脑上工作正常,但是当我用 iPhone 测试时,我发现 iOS 会上传任何同名的图片,例如 image.pngimage.jpeg.

使最后上传完成的图片替换之前上传成功的任何图片。

我在 Python3 中使用 boto3 生成预​​签名 post,如下所示:

post = s3.generate_presigned_post(
    Bucket='?????????',
    Key=get_random_string(8,'simple') + '/${filename}',
    Fields={
        'success_action_status': '201',
        'acl': 'public-read'
    },
    Conditions=[{
            'success_action_status': '201'
        },
        {
            'acl': 'public-read'
        },
        ["starts-with", "$Content-Type", ""]
    ]
)
post['fields'] = json.dumps(post['fields'])

这是我的 javascript 代码:

$(function () {
    'use strict';

    var form = $('#fileupload');
    // Initialize the jQuery File Upload widget:
    $('#fileupload').fileupload({
        dropZone: $('#dropzone'),
        previewMaxHeight: 300,
        previewMaxWidth: 300,
        acceptFileTypes:  /(\.|\/)(gif|jpe?g|png)$/i,
        dataType: 'XML',
        getFilesFromResponse: function (data) {
            var key = $(data.jqXHR.responseXML).find("Key").text();
            var url = $(data.jqXHR.responseXML).find("Location").text();
            return [{
                url: url,
                name: key,
                thumbnailUrl: url,
            }];
        },
    }).on('fileuploadsubmit', function (e, data) {
        data.formData = (function (form) {
            var r = form.serializeArray();
            $.each(form.data('theform-data'), function(k, v) {
                r.push({name: k , value: v})
            });
            return r;
        })(data.form);
        data.formData.push({name: "Content-Type" , value: data.files[0].type});
    });
});

Python中的get_random_string(8,'simple')只是可以防止不同文件上传同名,但是不能防止用户同时上传多个文件时重名(因为他们上传的是同一个pre-签名 POST url).

所以我想知道是否有任何方法可以在使用预签名 POST url 将文件上传到 AWS S3 时设置随机文件名?

我发现这行得通:

$(function () {
    'use strict';

    var form = $('#fileupload');
    // Initialize the jQuery File Upload widget:
    $('#fileupload').fileupload({
        dropZone: $('#dropzone'),
        previewMaxHeight: 300,
        previewMaxWidth: 300,
        acceptFileTypes:  /(\.|\/)(gif|jpe?g|png)$/i,
        dataType: 'XML',
        getFilesFromResponse: function (data) {
            var key = $(data.jqXHR.responseXML).find("Key").text();
            var url = $(data.jqXHR.responseXML).find("Location").text();
            return [{
                url: url,
                name: key,
                thumbnailUrl: url,
            }];
        },
    }).on('fileuploadsubmit', function (e, data) {
        data.formData = (function (form) {
            var r = form.serializeArray();
            $.each(form.data('theform-data'), function(k, v) {
                if (k == "key") {
                    var filename = v.split("/");
                    var random_prefix = filename[0];
                    var ext = data.files[0].name.split(".").slice(-1)[0];
                    v = random_prefix + '/'
                        + (function (length, chars) {
                            var result = '';
                            for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
                            return result;
                        })(10, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
                        + '.' + ext.toLowerCase();
                };
                r.push({name: k , value: v})
            });
            return r;
        })(data.form);
        data.formData.push({name: "Content-Type" , value: data.files[0].type});
    });
});