dropzone.js上传到AWS s3会为第3次以上的上传生成400(错误请求)

时间:2019-07-16 17:06:03

标签: amazon-web-services amazon-s3 aws-sdk dropzone.js

我正在尝试实现dropzone.js接口,以将文件上传到AWS S3。我遵循了一些在网上找到的示例

<html>
<head>
    <title>S3 Dropzone</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <link rel="stylesheet" href="https://rawgit.com/enyo/dropzone/master/dist/dropzone.css">
    <script src="https://rawgit.com/enyo/dropzone/master/dist/dropzone.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.476.0.min.js"></script>
    <script language="JavaScript">
        var bucket = "test-bucket";
        var region = "us-east-2";
        var userId = "11111";

        $(document).ready(function($) {
            $.ajax({
                url: "/s3_credentials.php",
                data: {},
                type: 'POST',
                dataType: 'json',
                success: function(response) {
                    bucket = response.Bucket;
                    region = response.region;
                    AWS.config.credentials = new AWS.Credentials({
                        accessKeyId:response.accessKeyId,
                        secretAccessKey:response.secretAccessKey
                    });
                    console.log("credentials response", response, AWS.config.credentials );
                }
            })
        });
        // let aws-sdk send events to dropzone.
        function sendEvents(file) {
            let progress = i => dz.emit('uploadprogress', file, i.loaded * 100 / i.total, i.loaded);
            file.s3upload.on('httpUploadProgress', progress);
            file.s3upload.send(err => err ? dz.emit('error', file, err) : dz.emit('complete', file));
        }

        Dropzone.prototype.uploadFiles = files => files.map(sendEvents);
    </script>

</head>

<body>

<br><br><br>

<h1 style="text-align: center">ImageUpload to S3Bucket</h1>
<div id="dz" class="dz-clickable dropzone"></div>

<script language="JavaScript">
    Dropzone.autoDiscover = false;
    let canceled = file => { if (file.s3upload) file.s3upload.abort() }
    let options = {
        url: '/',
        canceled,
        removedfile: canceled,
        accept(file, done) {
            let params = {
                Bucket: bucket,
                Key: userId + "/" + file.name,
                Body: file
            };
            params.accessKeyId = AWS.config.credentials.accessKeyId;
            params.secretAccessKey = AWS.config.credentials.secretAccessKey;
            console.log('upload params', params);
            file.s3upload = new AWS.S3.ManagedUpload({params});
            done();
        }
    };
    var dz = new Dropzone('#dz', options );
</script>
</body>
</html>

凭据脚本非常简单:

<?php
$AWSBucket = "dropzone-bucket-test";
$AWSRegion = "us-east-2";
$AWSUserArn = "arn:aws:iam::22222222222:user/test-bucket";
$AWSUserAccessKeyId = "*****************";
$AWSUserSecretAccessKey = "**********************************";

header('Content-Type: application/json');
echo json_encode([
    'Bucket'          => $AWSBucket,
    'accessKeyId'     => $AWSUserAccessKeyId,
    'secretAccessKey' => $AWSUserSecretAccessKey,
    'region'          => $AWSRegion,
    'userArn'         => $AWSUserArn
]);

第3次以上PUT调用返回的响应似乎表明该区域以某种方式回落到默认的us-east-1。我的代码都没有包含该区域信息,但是我在某些AWS SDK中将其视为默认区域。

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>AuthorizationHeaderMalformed</Code>
    <Message>The authorization header is malformed; the region 'us-east-1' is wrong; expecting 'us-east-2'</Message>
    <Region>us-east-2</Region>
    <RequestId>********************</RequestId>
    <HostId>***********************************************************************=</HostId>
</Error>

它将成功上传1或2个文件。在那之后,它似乎开始失败并显示400个错误。检查答复,这是说该地区是错误的,但我不确定它是如何发展的。我假设它已恢复为aws-sdk中的默认值,但我不确定为什么。

我甚至尝试过使用正确的值初始化变量,然后再执行凭据调用以从服务器获取配置的值。

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我不确定为什么您的代码会显示这种行为,但是对我来说似乎很奇怪的是第一个脚本的结构。您正在通过异步的AJAX调用在$(document).ready函数中获取凭据,但是负责// let aws-sdk send events to dropzone.的代码位于AJAX的成功处理程序之外,甚至位于$(document).ready函数的外部,这意味着它在使用这些凭证配置AWS SDK之前执行。

我建议将提到的代码放入AJAX的成功处理程序中。

<script language="JavaScript">
    var bucket = "test-bucket";
    var region = "us-east-2";
    var userId = "11111";

    function sendEvents(file) {
        let progress = i => dz.emit('uploadprogress', file, i.loaded * 100 / i.total, i.loaded);
        file.s3upload.on('httpUploadProgress', progress);
        file.s3upload.send(err => err ? dz.emit('error', file, err) : dz.emit('complete', file));
    }

    $(document).ready(function($) {
        $.ajax({
            url: "/s3_credentials.php",
            data: {},
            type: 'POST',
            dataType: 'json',
            success: function(response) {
                bucket = response.Bucket;
                region = response.region;
                AWS.config.credentials = new AWS.Credentials({
                    accessKeyId:response.accessKeyId,
                    secretAccessKey:response.secretAccessKey
                });
                console.log("credentials response", response, AWS.config.credentials);

                // let aws-sdk send events to dropzone.
                Dropzone.prototype.uploadFiles = files => files.map(sendEvents);
            }
        })
    });
</script>