因此,我在将文件直接上传到S3时遇到了一些麻烦。目前,我的流程是向nodejs / express请求以获取签名的URL。
app.post('/s3SignedURL', function(req, res){ var id = crypto.randomBytes(20).toString('hex'); var ext = path.extname(req.body.fileName); var unambFilename = path.basename(req.body.fileName, ext) + '-' + id + ext; var params = {Bucket: awsBucket, Key: unambFilename, Expires: 30}; var signedUrl = s3.getSignedUrl('putObject', params); res.send({signedUrl: signedUrl, s3FileName: unambFilename}); });
然后,我的角度控制器尝试使用该签名的URL($ scope.uploadDocument())直接上传到s3。
flqApp.controller('DocUploadModalCtrl', ['$scope', '$http', 'customProvider', 'custom', function($scope, $http, customProvider, custom){ $scope.fileTypes = [ "Type 1", "Type 2" ] $scope.setFile = function(element){ $scope.$apply(function($scope){ $scope.currentDocument = element.files[0]; }); } $scope.uploadDocument = function() { $http.post('/s3SignedURL', {fileName: $scope.currentDocument.name} ) .success(function(results){ $http.put(results.signedUrl, $scope.currentDocument) .success(function(){ custom.document = s3FileName; customProvider.save(custom, function(){ //..do something here }); }); }); }; }]);
我的html表单看起来像
<form ng-submit="uploadDocument()"> <label for="documentType">File Type</label> <select class="form-control" ng-model="docType" ng-options="type for type in fileTypes" required > <option value=""/> </select> <label for="filename">Choose file to upload</label> <input type="file" name="s3File" onchange="angular.element(this).scope().setFile(this)" ng-model="fileName" required /> <input type="submit" value="Upload File"> </form>
但是,每当我尝试上传到S3时,都会出现错误
Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin
我知道S3CORS在该存储桶的亚马逊端已正确设置,因为我已经开发了将相同存储桶用于开发存储的ruby应用程序。(请允许我使用回形针和雾器)。其次,由于我没有亚马逊响应的失败原因,所以我不怀疑错误是从那里来的。但是它确实来自我尝试将文件放在亚马逊上的那一行。
因此,我确定我会丢失某些内容,但是我认为使用签名URL,除了对该URL进行放置外,不需要任何其他操作。
我一直在这个问题上苦苦挣扎,终于弄明白了!我将详细说明我的步骤,希望它可以帮助一些人。
我使用了这个模块:https : //github.com/asafdav/ng-s3upload
我按照他们列出的步骤进行操作,即:
<?xml version="1.0" encoding="UTF-8"?> <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <AllowedMethod>POST</AllowedMethod> <AllowedMethod>PUT</AllowedMethod> <AllowedHeader>*</AllowedHeader> </CORSRule>
<?xml version="1.0"?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <allow-access-from domain="*" secure="false" /> </cross-domain-policy>
{ "policy":"XXX", "signature":"YYY", "key":"ZZZ" }
XXX-AWS要求的策略json,采用base64编码。 YYY-HMAC和您的私钥 ZZZ-您的公钥这是Rails的示例,即使您不是Rails开发人员,也请阅读代码,这非常简单。
这是最重要的步骤:确保您生成正确的策略文档。
这是我在C#中的代码
StringBuilder builder = new StringBuilder(); builder.Append("{") .Append("\"expiration\": \"") .Append(GetFormattedTimestamp(expireInMinutes)) .Append("\",") .Append("\"conditions\": [") .Append("{\"bucket\": \"") .Append(bucketName) .Append("\"},") .Append("{\"acl\": \"") .Append("public-read") .Append("\"},") .Append("[\"starts-with\", \"$key\", \"") .Append(prefix) .Append("\"],") .Append("[\"starts-with\", \"$Content-Type\", \"\"],") .Append("[ \"content-length-range\", 0, " + 10 * 1024 * 1024 + "]") .Append("]}"); Encoding encoding = new UTF8Encoding(); this.policyString = Convert.ToBase64String(encoding.GetBytes(builder.ToString().ToCharArray())); this.policySignature = SignPolicy(awsSecretKey, policyString);
这将生成以下Json
{ "expiration":"2014-02-13T15:17:40.998Z", "conditions":[ { "bucket":"bucketusaa" }, { "acl":"public-read" }, [ "starts-with", "$key", "" ], [ "starts-with", "$Content-Type", "" ], [ "content-length-range", 0, 10485760 ] ] }
然后,此文档经过base64编码,并作为字符串向下发送。
我的问题出在我的保单文件上。策略文档就像您为会话定义的一组规则,例如:文件名必须以某些东西开头(即,上传到子文件夹),大小必须在范围内。
使用适用于您的浏览器的开发人员工具,然后查看“网络”选项卡,查看AWS返回的错误,这确实对我有帮助,它将说明诸如策略错误之类的内容,并说明失败的条件。通常,您将获得访问被拒绝的错误,这将基于策略文档中设置的条件或错误的密钥。
某些浏览器的另一件事是localhost CORS出现问题。但是使用上述方法,我能够使用chrome从本地开发机上载文件。
Access-Control-Allow-Origin不允许来源’localhost:3000’
从您的错误看来,您尚未在AWS端设置CORS规则。