如何使用Meteor将文件上传到Amazon S3?

12

我正在尝试将文件上传到我的亚马逊S3存储桶。S3和亚马逊已经设置好了。 这是来自亚马逊的错误消息:

冲突的查询字符串参数: acl, policy

策略和签名已使用Crypto.js编码,用于Node.js

var crypto=Npm.require("crypto");

我正在尝试使用Meteor的HTTP.post方法构建POST请求。这可能也是错误的。

    var BucketName="mybucket";
    var AWSAccessKeyId="MY_ACCES_KEY";
    var AWSSecretKey="MY_SECRET_KEY";

    //create policy
    var POLICY_JSON={
        "expiration": "2009-01-01T00:00:00Z",
            "conditions": [ 
            {"bucket": BucketName}, 
            ["starts-with", "$key", "uploads/"],
            {"acl": 'public-read'},
            ["starts-with", "$Content-Type", ""],
            ["content-length-range", 0, 1048576],
        ]   
    }
    var policyBase64=encodePolicy(POLICY_JSON);
    //create signature
    var SIGNATURE = encodeSignature(policyBase64,AWSSecretKey);
    console.log('signature: ', SIGNATURE);

这是我在Meteor中使用的POST请求:

    //Send data----------
    var options={
        "params":{
            "key":file.name,
            'AWSAccessKeyId':AWSAccessKeyId,
            'acl':'public-read',
            'policy':policyBase64,
            'signature':SIGNATURE,
            'Content-Type':file.type,
            'file':file,
            "enctype":"multipart/form-data",
        }
    }

    HTTP.call('POST','https://'+BucketName+'.s3.amazonaws.com/',options,function(error,result){
        if(error){
            console.log("and HTTP ERROR:",error);
        }else{
            console.log("result:",result);
        }
    });

现在我正在对政策和签名进行编码:

encodePolicy=function(jsonPolicy){
    // stringify the policy, store it in a NodeJS Buffer object
    var buffer=new Buffer(JSON.stringify(jsonPolicy));
    // convert it to base64
    var policy=buffer.toString("base64");
    // replace "/" and "+" so that it is URL-safe.
    return policy.replace(/\//g,"_").replace(/\+/g,"-");
}

encodeSignature=function(policy,secret){
    var hmac=crypto.createHmac("sha256",secret);
    hmac.update(policy);
    return hmac.digest("hex");
}

A无法确定发生了什么问题。可能在POST方法或加密时已经存在问题,因为我对这些方法不太熟悉。如果有人能引导我正确地进行编码或将POST请求正确发送到AmazonS3,那将会非常有帮助。
(我不喜欢使用filepicker.io,因为我不想强迫客户在那里注册。)

提前感谢了!


queryString不等同于POST参数,也许你需要在GET URL上复制这两个被抱怨的参数... - dandavis
4个回答

6
直接上传到S3,您可以使用slingshot包:
meteor add edgee:slingshot

在服务器端声明您的指令:
Slingshot.createDirective("myFileUploads", Slingshot.S3Storage, {
  bucket: "mybucket",
  allowedFileTypes: ["image/png", "image/jpeg", "image/gif"],

  acl: "public-read",

  authorize: function () {
    //You can add user restrictions here
    return true;
  },

  key: function (file) {
    return file.name;
  }
});

这个指令会自动生成策略和签名。 然后像这样上传:
var uploader = new Slingshot.Upload("myFileUploads");

uploader.send(document.getElementById('input').files[0], function (error, url) {
  Meteor.users.update(Meteor.userId(), {$push: {"profile.files": url}});
});

这是一个相当古老的问题,那时还没有Slingshot包。现在有了,而且非常好用。可以直接从浏览器上传文件,因此我接受这个答案,而不是Hubert的服务器端解决方案。 感谢分享! - zalavari

5
为什么不使用 aws-sdk 包呢?它为您提供了所有必要的方法。例如,这是向存储桶添加文件的简单函数:
s3.putObject({
  Bucket: ...,
  ACL: ...,
  Key: ...,
  Metadata: ...,
  ContentType: ...,
  Body: ...,
}, function(err, data) {
  ...
});

1
谢谢,这个很明显啊。我甚至不知道我怎么错过了这个包。我现在就去试试看。 - zalavari
你是否正确发送了它?这可能有点棘手。如果您在配置方面遇到问题,最好打开一个新的问题,因为这是一个不同的问题。 - Hubert OG
我开了一个新的问题:https://dev59.com/aHjZa4cB1Zd3GeqPdWbl - zalavari

1

请查看S3 Meteor 包。自述文件中有非常全面的入门指南。


0

首先需要添加用于S3文件上传的软件包。

安装:添加(AWS SDK智能软件包) $ meteor add peerlibrary:aws-sdk

1.创建指令upload.js并粘贴以下代码。

angular.module('techno')
.directive("fileupload", [function () {
    return {
        scope: {
            fileupload: "="
        },
        link: function(scope,element, attributes){
            $('.button-collapse').sideNav();
            element.bind("change", function (event) {
                scope.$apply(function () {
                 scope.fileupload = event.target.files[0];
             });
           })
       }};
}]);

2. 获取Access密钥并将其粘贴到您的 fileUpload.js 文件中。

AWS.config.update({
accessKeyId: ' AKIAJ2TLJBEUO6IJLKMN ',
secretAccessKey: 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'
});

AWS.config.region = 'us-east-1';
let bucket = new AWS.S3();

3.现在将这个上传代码放入您的指令fileUpload.js

vm.upload = (Obj) =>{
vm.loadingButton = true;
let name = Obj.name;
let params = {
    Bucket: 'technodheeraj',
    Key: name,
    ContentType: 'application/pdf',
    Body: Obj,
    ServerSideEncryption: 'AES256'
};

bucket.putObject(params, (err, data) => {
    if (err) {
        console.log('---err------->', err);
    }
    else {
        vm.fileObject = {
            userId: Meteor.userId(),
            eventId: id,
            fileName: name,
            fileSize: fileObj.size,
        };
   vm.call("saveFile", vm.fileObject, (error, result) => {
            if (!error){
                console.log('File saved successfully');

            }
        })
    }
})

};

4.现在在“saveFile”方法中粘贴此代码

saveFile: function(file){
if(file){
    return Files.insert(file);
}

};

5.在HTML中粘贴此代码

<input type="file" name="file" fileupload="file">
<button type="button" class="btn btn-info " ng-click="vm.upload(file)"> Upload File</button>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接