从上传的文件angularjs直接到Amazon S3使用签名的网址 [英] upload file from angularjs directly to amazon s3 using signed url

查看:814
本文介绍了从上传的文件angularjs直接到Amazon S3使用签名的网址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一些麻烦,直接上传文件到S3。目前,我的过程是使请求nodejs / EX preSS获得签名的URL。

  app.post('/ s3SignedURL',功能(REQ,RES){
  变种的id = crypto.randomBytes(20)的ToString('进制');
  VAR EXT = path.extname(req.body.fileName);
  VAR unambFilename = path.basename(req.body.fileName,分机)+' - '+编号+分机;
  VAR PARAMS = {斗:awsBucket,重点:unambFilename,截止日期:30};
  VAR signedUrl = s3.getSignedUrl('putObject',则params);

  res.send({signedUrl:signedUrl,s3FileName:unambFilename});
});
 

我的角度控制器,然后尝试直接上传到S3使用该标识的URL($ scope.uploadDocument())

  flqApp.controller(DocUploadModalCtrl',['$范围,$ HTTP,customProvider,自定义,
  功能($范围,$ HTTP,customProvider,自定义){

  $ scope.fileTypes =
  [
    类型1,
    第二类
  ]

  $ scope.setFile =功能(元素){
    $范围。$应用(功能($范围){
      $ scope.currentDocument = element.files [0];
    });
  }

  $ scope.uploadDocument =功能(){
    $ http.post('/ s3SignedURL',{文件名:$ scope.currentDocument.name})
     .success(函数(结果){
      $ http.put(results.signedUrl,$ scope.currentDocument)
       .success(函数(){
        custom.document = s3FileName;
        customProvider.save(自定义,函数(){
        这里//..do东西
        });
      });
    });
  };
}]);
 

我的HTML表单的外观

 <形式NG提交=uploadDocument()>
  <标签=documentType>文件类型< /标签>
  <选择类=表单控制NG-模式=DOCTYPE的文件类型类型类型NG-选项=所需>
    <期权价值=/>
  < /选择>
  <标签=文件名>选择要上传的文件< /标签>
  <输入类型=文件
     NAME =s3File
     的onchange =angular.element(本).scope()。setFile(本)
     NG-模式=文件名
     要求/>

  <输入类型=提交值=上传文件>
< /形式GT;
 

不过每当我试图上传到S3我的错误

 产地的http://本地主机:3000没有被允许访问控制 - 允许 - 原产地
 

我知道,S3 CORS是正确设置,在亚马逊年底,该水桶,因为我已经开发了使用相同的桶开发存储红宝石的应用程序。 (当然我是用曲别针和放大器;雾的)。其次,因为我没有失败赶上亚马逊的反应,我不怀疑的错误是从那里来。然而,它确实来自哪里我试图把文件在亚马逊的线上。

所以,我相信,我失去了一些东西,但是我觉得有符号的URL我不需要任何超过做一个向他提出的网址。

解决方案

我一直在挣扎了很多这个问题终于想通弄明白了!我将详细介绍我的步骤,希望这可以帮助一些一出。

我用这个模块: https://github.com/asafdav/ng-s3upload

我跟着他们上市,即步骤:

  1. 创建一个桶
  2. 资助把/删除:扩大权限部分,并点击添加更多的权限所有人和上传/删除保存
  3. 按钮来选择。
  4. 添加CORS的配置:

     < XML版本=1.0编码=UTF-8&GT?;
    < CORSConfiguration的xmlns =htt​​p://s3.amazonaws.com/doc/2006-03-01/>
        < CORSRule>
            < AllowedOrigin> *< / AllowedOrigin>
            < AllowedMethod> GET< / AllowedMethod>
            < AllowedMethod> POST< / AllowedMethod>
            < AllowedMethod> PUT< / AllowedMethod>
            < AllowedHeader> *< / AllowedHeader>
        < / CORSRule>
     

  5. 添加的crossdomain.xml你斗的制作根其公开

     < XML版本=1.0&GT?;
    <!DOCTYPE跨域,政策体系
    http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
    <交域政策>
      <允许存取来自域=*安全=FALSE/>
    < /跨域策略>
     

  6. 创建返回JSON具有以下服务:

      {
       政策:XXX,
       签名:YYY
       钥匙:ZZZ
    }
     

  

  • XXX - 即要求AWS,BASE64 EN $ C $光盘政策JSON。
  • YYY - HMAC和你的私钥SHA
  • 在ZZZ - 你的公钥这里有一个 轨道例如,即使你不是一个Rails开发者,请阅读code, 这是非常简单的。

这是最重要的一步:请确保您生成正确的政策文件。

下面是我的code在C#

  StringBuilder的建设者=新的StringBuilder();
        builder.Append({)
                .Append(\过期\:\)
                .Append(GetFormattedTimestamp(expireInMinutes))
                。附加(\,)
                .Append(\条件\:[)
                .Append({\斗\:\)
                .Append(bucketName)
                。附加(\},)
                .Append({\ACL \:\)
                .Append(大众阅读的)
                。附加(\},)
                .Append([\开始,以\,\$键\,\)
                .Append(preFIX)
                。附加(\],)
                .Append([\开始,以\,\$内容类型\,\\])
                .Append([\内容长度范围\,0,+ 10 * 1024 * 1024 +])
                。附加(]});
        编码编码=新UTF8Encoding();
        this.policyString = Convert.ToBase64String(encoding.GetBytes(builder.ToString()ToCharArray())。);
        this.policySignature = SignPolicy(awsSecretKey,policyString);
 

这会产生下面的JSON

  {
   过期:2014-02-13T15:17:40.998Z
   条件:
      {
         斗:bucketusaa
      },
      {
         以acl:公共 - 读
      },
      [
         开始,以
         $关键,
         
      ]
      [
         开始,以
         $内容类型,
         
      ]
      [
         内容长度范围,
         0,
         10485760
      ]
   ]
}
 

本文档是那么的base64 EN codeD并派下来作为一个字符串。

我的问题是我的政策文件。该政策文件是像一组规则定义的会议,如:文件名必须以东西(即上传到子文件夹),规模必须在范围内。

使用的开发工具为您的浏览器,看看在网络选项卡,看看有什么错误AWS正在返回这真的帮了我,它会说明一些类似下面的政策错误,说什么条件失败。你通常会得到拒绝访问错误,这将是基于策略的文档或错键设置的条件。

另一件事某些浏览器与本地主机CORS问题。但使用上述我能够使用镀铬从我的本地开发计算机上传文件。

  

产地本地主机:3000没有被访问控制 - 允许 - 原产地允许

从你的错误看起来你还没有建立CORS规则的AWS的一面。

So I am having some trouble uploading a file directly to S3. Currently my process is to make a request to nodejs/express to get a signed 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});
});

My angular controller then tries to upload directly to s3 using that signed URL ($scope.uploadDocument())

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
        });
      });
    });
  };
}]);

My html form looks like

<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>

However whenever I try to upload to S3 I get the error

Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin

I know that S3 CORS is setup correctly, on the amazon end, for that bucket, because I have developed ruby apps that use the same bucket for development storage. (granted I was using paperclip & fog for those). Secondly, since I don't have a failure catch for the amazon response, I don't suspect the error to be coming from there. However it does come from the line where I try to put the file on amazon.

So I am sure I am missing something, but I thought that with signed URL's I don't need anything more than to do a put to that url.

解决方案

I have been struggling a lot with this issue and finally got it figured out! I will detail my steps, hopefully it can help some one out.

I used this module: https://github.com/asafdav/ng-s3upload

I followed the steps they listed, namely:

  1. Create a Bucket
  2. Grant "put/Delete: expand the "Permissions" sections and click on the "Add more permissions" button. Select "Everyone" and "Upload/Delete" and save.
  3. Add CORS Configuration:

    <?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>
    

  4. Add "crossdomain.xml" to the root of your bucket making it public

    <?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>
    

  5. Create a service that will return JSON with the following:

    {
       "policy":"XXX",
       "signature":"YYY",
       "key":"ZZZ"
    }
    

  • XXX - A policy json that is required by AWS, base64 encoded.
  • YYY - HMAC and sha of your private key
  • ZZZ - Your public key Here's a rails example, even if you're not a rails developer, read the code, it's very straight forward.

This is the most important step: make sure you are generating the correct policy document.

Here is my code in 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);

This generates the following 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
      ]
   ]
}

This document is then base64 encoded and sent down as a string.

My issue was with my policy document. The policy document is like a set of rules you define for the session like: file names must start with something (ie. upload to a subfolder), the size must be in the range.

Use the developer tools for your browser, and take a look at the network tab, see what errors AWS are returning this really helped me, it will state things like policy errors and say what condition failed. You will generally get access denied errors and this will be based on the conditions set in the policy document or wrong keys.

One other thing some browsers have issues with localhost CORS. But using the above I was able to upload files from my local dev machine using chrome.

Origin 'localhost:3000' is not allowed by Access-Control-Allow-Origin

From your error it looks like you have not set up the CORS rules on the AWS side.

这篇关于从上传的文件angularjs直接到Amazon S3使用签名的网址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆