S3通过角度上传

时间:2014-01-15 06:08:57

标签: angularjs amazon-s3

使用this plugin

Sooooo我有一个问题

因此,我在我的服务器上生成一个已签名的S3网址,并尝试使用此插件上传。我可以使用

生成网址并上传文件 它之前是如何运作的

shell curl -T file.jpg http://bla.s3.amazon.com/blahbahbla

我是怎么做的

当我尝试从浏览器上传文件时

```的JavaScript

$upload.http({
   url:    decodeURIComponent(data.signed_url),
   method: 'PUT',
   data:   file,
   headers: {
    'Content-Type':file.type,
   }
}).progress(function(evt) {

    console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));

}).success(function(data, status, headers, config) {

    console.log(data);

}).error(function(data, status, headers, config) {

    console.warn(data, status);

});

```

响应

我收到了这样的回复

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><StringToSignBytes>50 55 54 0a 0a 69 6d 61 67 65 2f 6a 70 65 67 0a 31 34 35 32 38 37 39 36 38 36 0a 78 2d 61 6d 7a 2d 61 63 6c 3a 70 75 62 6c 69 63 2d 72 65 61 64 0a 2f 62 67 70 72 6f 6f 66 2f 66 61 63 65 62 6f 6f 6b 3a 31 30 30 30 30 33 34 37 31 35 37 34 31 30 35 2f 33 65 31 62 36 64 32 39 2d 62 66 34 31 2d 34 37 62 31 2d 61 35 31 33 2d 30 38 38 61 39 63 30 32 61 39 62 63 2e 6a 70 67</StringToSignBytes><RequestId>CE628CB59F561A3D</RequestId><HostId>u5iLkvYLE0hRj30IU+qMS+XiwlwY/VXt8ZACxyot2KDwnLw5S2HL/pGgk4F/nHfr</HostId><SignatureProvided>hJg fYN2h6qz9jJATt4Zp A C94=</SignatureProvided><StringToSign>PUT

image/jpeg
1452879686
x-amz-acl:public-read
/kirkstrobeck/facebook:100003471574105/3e1b6d29-bf41-47b1-a513-088a9c02a9bc.jpg</StringToSign><AWSAccessKeyId>MY_ACCESS_KEY</AWSAccessKeyId></Error>

以下是两个请求的标头

请求标题
PUT /facebook:100003471574105/3e1b6d29-bf41-47b1-a513-088a9c02a9bc.jpg?AWSAccessKeyId=MY_ACCESS_KEY&Expires=1452879686&Signature=hJg+fYN2h6qz9jJATt4Zp+A+C94=&x-amz-acl=public-read HTTP/1.1
Host: kirkstrobeck.s3.amazonaws.com
Connection: keep-alive
Content-Length: 362867
Cache-Control: no-cache
Pragma: no-cache
Accept: application/json, text/plain, */*
Origin: http://localhost:5005
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Content-Type: image/jpeg
Referer: http://localhost:5005/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Res标题
HTTP/1.1 403 Forbidden
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, PUT, DELETE
Access-Control-Max-Age: 10000
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
x-amz-request-id: CE628CB59F561A3D
x-amz-id-2: u5iLkvYLE0hRj30IU+qMS+XiwlwY/VXt8ZACxyot2KDwnLw5S2HL/pGgk4F/nHfr
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Wed, 15 Jan 2014 05:41:26 GMT
Connection: close
Server: AmazonS3

这就是我们在NodeJS中生成带符号的putObject网址的方法

var uuid = require('node-uuid');
var AWS  = require('aws-sdk');
var s3   = new AWS.S3({
    apiVersion:      '2014-01-10',
    accessKeyId:     'AWS_ACCESS_KEY',
    secretAccessKey: 'AWS_SEC_ACCESS_KEY'
});


module.exports =  function (req, res, next) {
    var exten   = req.param('ext');
    var expire  = req.param('expire');

    var key = uuid.v4() + exten;
    var params  = {
        Bucket:  'BUCKET_NAME',
        Key:     key,
        Expires: 900,
        ACL: 'public-read'
    };

    s3.getSignedUrl('putObject', params, function(err, url){
        // ..  handle callback
    });
};

3 个答案:

答案 0 :(得分:1)

这个例子可能会有所帮助: https://github.com/bookingbricks/file-upload-example 使用:Node,aws-sdk-js,jQuery-file-upluad(blueimp)

服务器:

var AWS = require('aws-sdk');

AWS.config.update({accessKeyId: AWS_ACCESS_KEY, secretAccessKey:     AWS_SECRET_KEY});
AWS.config.region = 'eu-west-1';

app.post('/s', function (req, res) {
    var s3 = new AWS.S3();
    var params = {Bucket: 'BUCKETNAME', Key: req.body.name, ContentType: req.body.type};
    s3.getSignedUrl('putObject', params, function(err, url) {
        if(err) console.log(err);
        res.json({url: url});
    });
});

客户端:

$.ajax({
    url: '/s',
    type: 'POST',
    data: {name: file.name, size: file.size, type:file.type},
}).success(function(res){
    $.ajax({
        url: res.url,
        type: 'PUT',
        data: file,
        processData: false,
        contentType: file.type,
    }).success(function(res){
        console.log('Done');
    });

答案 1 :(得分:0)

S3对通过POST上传文件有非常具体的要求。有些特定的输入字段需要您的请求中似乎缺少值。

查看必填字段的文档:http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingHTTPPOST.html

答案 2 :(得分:0)

通过http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html查看,看起来您正在使用查询字符串身份验证方法,因此您的请求必须采用

形式
GET /my-bucket/foo
 ?Signature=<urlencode(base64(hmac-sha1(VERB + "\n" + CONTENT-MD5 + "\n" + CONTENT-TYPE + "\n" + Expires + "\n" + CanonicalizedAmzHeaders + "\n" + CanonicalizedResource)))>
 &Expires=<seconds since epoch>
 &AWSAccessKeyId=<aws-id>

解决其中的每一项,比较如何使用请求本身生成签名请求

VERB:根据http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html使用'putObject'是请求签署PUT请求的正确方法。您的请求标头似乎使用了PUT请求。

CONTENT-MD5:您在服务器上签署请求时未指定ContentMD5选项。根据文档,这是可选的,但是必须在计算签名的字符串中包含空字符串+新行。因此,您可能需要向传递给ContentMD5的{​​{1}}对象添加空params参数

内容类型:getSignedUrl也是可选的。但是,我注意到您在PUT请求中发送ContentType标头,但在生成签名时未指定它。因此,S3可以使用它来生成签名以进行检查,并使请求失败。我建议在生成签名时将ContentType设置为浏览器中的内容,或者在两种情况下都将其设置为空(可能将空字符串传递给调用ContentType

过期:来自文档:

  

Expires字段以纪元时间以来的秒数为单位

我不确定Node API如何使用getSignedUrl选项,但将其设置为900可能意味着它已经过期。你写的网址输出为1452879686,即2014年1月20日。鉴于你的问题写于1月15日/ 17日,我不确定这是如何匹配的。我会确切地检查您需要传递的内容Expires,并尝试将完整日期传递给'getSignedUrl'调用。

CanonicalizedAmzHeaders:从我所看到的,对Expires的调用添加了getSignedUrl,因此我只能假设它在生成网址时使用了它。

CanonicalizedResource:我再次假设对x-amz-acl=public-read的调用正确使用了这个。

AWSAccessKeyId:它位于生成的URL中,因此我假设getSignedUrl正确使用了它。

总结:

  • ContentMD5:将其设置为getSignedUrl对象
  • 中的空字符串
  • 确保在生成签名时指定ContentType,并使其与PUT请求相同(或为空或params
  • 将完整日期设置为params对象image/jpeg的{​​{1}}选项,并检查生成的URL是否合理。