【问题标题】:Errors when posting from AngularJS to Amazon S3从 AngularJS 发布到 Amazon S3 时出错
【发布时间】:2013-10-14 18:10:04
【问题描述】:

我正在 MEAN(MongoDB、Express、AngularJS、node.js)堆栈上构建一个应用程序,需要将图像文件上传到 Amazon S3。我的做法如下:

首先,将 http get 发送到我的 API,它指定交互的“策略文档”并将其返回到 AngularJS 前端。该后端代码如下所示(填充了变量):

exports.S3Signing = function(req, res) {
    var bucket = "MY_BUCKET_NAME",
        awsKey = "MY_AWS_KEY",
        secret = "MY_SECRET",
        fileName = req.params.userId,
        expiration = new Date(new Date().getTime() + 1000 * 60 * 5).toISOString();

    var policy = { 
        "expiration": expiration,
        "conditions": [
            {"bucket": bucket},
            {"key": fileName},
            {"acl": 'public-read'},
            ["starts-with", "$Content-Type", ""],
            ["content-length-range", 0, 524288000]
        ]};

    policyBase64 = new Buffer(JSON.stringify(policy), 'utf8').toString('base64');
    signature = crypto.createHmac('sha1', secret).update(policyBase64).digest('base64');
    res.json({bucket: bucket, awsKey: awsKey, policy: policyBase64, signature: signature});
};

这个进程的前端 (AngularJS) 代码如下所示:

$http.get('/api/v1/auth/signS3/' + userId).success(function(data, status) {
                var formData = new FormData();
                formData.append('key', userId);
                formData.append('AWSAccessKeyId', data.awsKey);
                formData.append('acl', 'public-read');
                formData.append('policy', data.policy);
                formData.append('signature', data.signature);
                formData.append('Content-Type', image.type);
                formData.append('file', image);

                $http({
                    method: 'POST',
                    url: 'http://' + data.bucket + '.s3.amazonaws.com/',
                    headers: {'Content-Type': 'multipart/form-data'},
                    data: formData
                }).success(function(data) {
                    deferred.resolve(data);
                }).error(function(err) {
                    deferred.reject(err);
                });
            }).error(function(err, status) {
                deferred.reject(err);
            });

但是,就目前而言,如果我发布图片,我会收到以下错误:

Malformed POST Request The body of your POST request is not well-formed multipart/form-data.

如果我将 http POST 调用更改为 AngularJS 简写并删除 "content-type": "multipart/form-data" 规范,如下所示:

$http.post('http://' + data.bucket + '.s3.amazonaws.com/', formData).success(function(data) {
                    deferred.resolve(data);
                }).error(function(err) {
                    deferred.reject(err);
                });

我收到以下错误:

 Precondition Failed At least one of the pre-conditions you specified did not hold Bucket POST must be of the enclosure-type multipart/form-data

我尝试了任何我能想到的条件和规格组合。我在这里错过了什么?

【问题讨论】:

标签: javascript node.js angularjs amazon-s3


【解决方案1】:

我认为问题出在我尝试上传的“文件”的格式上。我使用的是this AngularJS 指令,它返回调整大小图像的格式不是实际文件。我仍在使用相同的指令,但不再使用图像大小调整。

我更改了上传过程的结构,以便在 node.js 后端完成大部分工作。 AngularJS 函数如下所示:

uploadImage: function(image, userId) {
            var deferred = $q.defer(),
                formData = new FormData();

            formData.append('image', image, image.name);

            $http.post('/api/v1/user/' + userId + '/image', formData, {
                transformRequest: angular.identity,
                headers: { 'Content-Type': undefined }
            }).success(function(data, status) {
                deferred.resolve(data);
            }).error(function(err, status) {
                deferred.reject(err);
            });

            return deferred.promise;
        }

要发布的 node.js/express 端点如下所示:

exports.uploadImage = function(req, res) {
    postToS3 = function(image, userId) {
        var s3bucket = new AWS.S3({params: {Bucket: config.aws.bucket}}),
            deferred = Q.defer(),
            getExtension = function(filename) {
                var i = filename.lastIndexOf('.');
                return (i < 0) ? '' : filename.substr(i);
            },
            dataToPost = {
                Bucket: config.aws.bucket,
                Key: 'user_imgs/' + userId + getExtension(image.name),
                ACL: 'public-read',
                ContentType: image.type
            };

        fs.readFile(image.path, function(err, readFile) {
            dataToPost.Body = readFile;

            s3bucket.putObject(dataToPost, function(err, data) {
                if (err) {
                  deferred.reject(err.message);
                } else {
                  deferred.resolve(data);
                }
            });
        });

        return deferred.promise;
    };

    postToS3(req.files.image, req.params.userId).then(function(data) {
        res.json(200, data);
    }, function(err) {
        res.send(500, err);
    })
};

现在使用亚马逊的AWS sdk for node.js

【讨论】:

    【解决方案2】:

    最近我也遇到了同样的问题。您需要将dataURI 转换为Blob 并上传从此函数返回的文件。使用 S3 上传可以正常上传。

    function dataURItoBlob(dataURI) {
        // convert base64/URLEncoded data component to raw binary data held in a string
        var byteString;
        if (dataURI.split(',')[0].indexOf('base64') >= 0)
            byteString = atob(dataURI.split(',')[1]);
        else
            byteString = unescape(dataURI.split(',')[1]);
    
        // separate out the mime component
        var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
    
        // write the bytes of the string to a typed array
        var ia = new Uint8Array(byteString.length);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
    
        return new Blob([ia], {type:mimeString});
    }
    

    【讨论】:

      【解决方案3】:

      如果你只删除应该工作:

      headers: {'Content-Type': 'multipart/form-data'},
      

      对于图片,我刚刚发送了类似的内容:

      $("#your_image_id").files[0]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-15
        • 1970-01-01
        • 2017-01-10
        • 1970-01-01
        • 1970-01-01
        • 2019-12-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多