AngularJs图片上传到S3 [英] AngularJs Image upload to S3

查看:524
本文介绍了AngularJs图片上传到S3的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我:结果
- 创建Web应用 -
- AngularJS前端与NG-文件上传( https://github.com/danialfarid/ng-file -upload )结果
- Node.js的后端结果
- 希望能够上传图片到我的Amazon S3的桶结果

我试图遵循本教程:
https://github.com/danialfarid/ng-file-upload/wiki/Direct-S3-upload-and-Node-signing-example

从本质上讲程序流程是选择该文件,点击一个按钮,要求从后端签署,然后上传到S3。

我收到从code 200,但后端的签字时,前端试图上传我看到这个在开发者菜单中的图像:结果
选项https://mybucket.name.s3-us-east-1.amazonaws.com/网:: ERR_NAME_NOT_RESOLVED

这是我的code,这是问题或建立我斗?的方式

加code如果需要的话:

在我的S3存储桶CORS

 <?XML版本=1.0编码=UTF-8&GT?;
< CORSConfiguration的xmlns =htt​​p://s3.amazonaws.com/doc/2006-03-01/>
    < CORSRule>
        < AllowedOrigin> * LT; / AllowedOrigin>
        < AllowedMethod> GET< / AllowedMethod>
        < MaxAgeSeconds> 3000 LT; / MaxAgeSeconds>
        < AllowedHeader>授权< / AllowedHeader>
    < / CORSRule>
    < CORSRule>
        < AllowedOrigin> my.computers.IP.Address< / AllowedOrigin>
        < AllowedMethod>放< / AllowedMethod>
        < AllowedMethod>信息< / AllowedMethod>
        < AllowedMethod>删除< / AllowedMethod>
        < AllowedHeader> * LT; / AllowedHeader>
    < / CORSRule>
< / CORSConfiguration>

Node.js的后端code

  app.post('/签约,功能(REQ,RES){
    VAR请求= req.body;
    变种文件名= request.filename    变种延长= fileName.substring(fileName.lastIndexOf()'。');
    VAR今天=新的Date();
    VAR路径=/+ today.getFullYear()+'/'+ today.getMonth()+'/'+ today.getDate()+'/'+ uuid.v4()+扩展名;    VAR readType ='私人';    VAR到期=时刻()加(5,'M')TODATE()。 //15分钟    VAR s3Policy = {
        过期:到期,
        '条件': [{
                '斗':aws.bucket
            },
            ['开始,用','$钥匙,路径]
            {
                '的ACL':readType
            },
            {
              success_action_status':'201'
            },
            ['开始,用','$ Content-Type的',request.type]
            [内容长度范围,2048,10485760],//最小值和最大值
        ]
    };    VAR stringPolicy = JSON.stringify(s3Policy);
    VAR base64Policy =新的缓冲区(stringPolicy,'utf-8')的toString('的base64')。    // SIGN政策
    VAR签名= crypto.createHmac(SHA1,aws.secret)
        .update(新的缓冲区(base64Policy,'utf-8'))消化('的base64')。    VAR凭证= {
        网址:s3Url,
        字段:{
            键:路径,
            AWSAccessKeyId:aws.key,
            ACL:readType,
            政策:base64Policy,
            签名:签名,
            内容类型:request.type,
            success_action_status:201
        }
    };
    res.jsonp(凭证);
});

AngularJS前端code

  App.controller('MyCtrl2',['$范围,$ HTTP','上传','$超时',函数($范围,$ HTTP,上传, $超时){
    $ scope.uploadPic =功能(文件){
        变种文件名= file.name;
        VAR类型= file.type;
        VAR的查询= {
            文件名:文件名,
            型:
        };
        $ http.post('/签约,查询)
            .success(功能(结果){
                Upload.upload({
                    网址:result.url,// s3Url
                    transformRequest:功能(数据,headersGetter){
                        变种头= headersGetter();
                        删除headers.Authorization;
                        返回的数据;
                    },
                    字段:result.fields,//证书
                    方法:POST,
                    文件:文件
                })。进度(功能(EVT){
                    的console.log('进步:+ parseInt函数(100.0 * evt.loaded / evt.total));
                })。成功(功能(数据,状态,头,配置){
                    //文件被上传成功
                    的console.log('文件'+ config.file.name +'成功上传响应:+数据);
                })错误(函数(){                });
            })
            .error(功能(数据,状态,头,配置){
                //异步调用,如果发生错误
                //或服务器返回的响应与一个错误状态。
        });
    };
}]);


解决方案

该示例包含的东西我会考虑过于简单化的错误。

  VAR s3Url =的https://+ aws.bucket +'.s3-'+ aws.region +'.amazonaws.com';

这工作多的时间,但它不是一个的始终的在S3中制作一个URL到对象的有效方式。

它打破了至少两例,其中之一是您所遇到的人。

对于S3的美国标准区域,它位于在美国东部-1 AWS的区域,是不是 S3端点-us-east-1.amazonaws.com ,因为这将是,如果使用相同的格式,对所有其他地区。对于显示的内容是传统的/进化的原因,那简直就是 s3.amazonaws.com ,但也可以写成 S3-外部1.amazonaws。 COM 。 (记住,S3已经有将近十年截至记者发稿,服务扩大和发展,同时向后保持compatibiliy - 一个值得注意的壮举,但势必会导致一些约定见于乍一看混淆)

不过,所有桶 - 包括那些不是我们 - 东 - 1 - 但不包括那些将打破上述code的第二个原因(我还没有得到到尚未) - 可简单地称呼为 bucket-name.s3.amazonaws.com - 如果你想了解更多关于DNS的分层特性,你可以看到这是如何可能的工作:S3,在几创建一个水桶分钟后,重新映射一个特定的主机名,DNS中,将请求发送到正确的区域S3终点。

所以 +'.s3-'+ aws.region + 应该工作,如果写的,简单地说, +'.S3'+

...除非,当然,你已经创造了在其名称中带点桶。在这种情况下,你将不得不以https问题(这是问题#2,上面提到的),因为名称中带点水桶将不匹配的通配符SSL(TLS)证书$ P $由S3 psented(设计限制在SSL通配符证书,而不是S3本身)。

如果这是一个问题,并使用在名称中没有点的桶是不可取的某些原因,你的URL必须在什么所谓的路径式的格式制作。这是替代的虚拟式的格式,其中桶名称是主机名。这里,铲斗名称是路径的第一部分

  https://开头S3 [-region] .amazonaws.com / bucket.name.with.dots /关键路径

...并再次,第一个组件就是 S3 S3-外部-1 美国标准(美国东部-1)...但是使用这种格式需要你相匹配的区域,不同的是如上所述,在DNS处理请求路由...否则S3将抛出一个永久重定向错误。

http://docs.aws.amazon.com/AmazonS3/最新的/ dev / VirtualHosting.html

http://docs.aws.amazon.com/通用/最新/ GR / rande.html#s3_region

这是很多信息,但不仅解释你需要做什么不同的希望对大家有用,但也是为什么。

I am:
- Creating a Web Application
- AngularJS front end with ng-file upload (https://github.com/danialfarid/ng-file-upload)
- Node.js backend
- Want to be able to upload images to my Amazon S3 bucket

I'm attempting to follow this tutorial: https://github.com/danialfarid/ng-file-upload/wiki/Direct-S3-upload-and-Node-signing-example

Essentially the program flow is select the file, click a button, request signing from the backend and then upload to S3.

I receive the signing from the backend with code 200 but when the frontend attempts to upload the image I see this in the developer menu:
OPTIONS https://mybucket.name.s3-us-east-1.amazonaws.com/ net::ERR_NAME_NOT_RESOLVED

Is it my code that is the problem or the way I set up my bucket?

Added Code if needed:

CORS on my S3 bucket

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>my.computers.IP.Address</AllowedOrigin>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Node.js Backend Code

app.post('/signing', function(req, res) {
    var request = req.body;
    var fileName = request.filename

    var extension = fileName.substring(fileName.lastIndexOf('.'));
    var today = new Date();
    var path = '/' + today.getFullYear() + '/' + today.getMonth() + '/' + today.getDate() + '/' + uuid.v4() + extension;

    var readType = 'private';

    var expiration = moment().add(5, 'm').toDate(); //15 minutes

    var s3Policy = {
        'expiration': expiration,
        'conditions': [{
                'bucket': aws.bucket
            },
            ['starts-with', '$key', path], 
            {
                'acl': readType
            },
            {
              'success_action_status': '201'
            },
            ['starts-with', '$Content-Type', request.type],
            ['content-length-range', 2048, 10485760], //min and max
        ]
    };

    var stringPolicy = JSON.stringify(s3Policy);
    var base64Policy = new Buffer(stringPolicy, 'utf-8').toString('base64');

    // sign policy
    var signature = crypto.createHmac('sha1', aws.secret)
        .update(new Buffer(base64Policy, 'utf-8')).digest('base64');

    var credentials = {
        url: s3Url,
        fields: {
            key: path,
            AWSAccessKeyId: aws.key,
            acl: readType,
            policy: base64Policy,
            signature: signature,
            'Content-Type': request.type,
            success_action_status: 201
        }
    };
    res.jsonp(credentials);
});

AngularJS frontend code

App.controller('MyCtrl2', ['$scope', '$http', 'Upload', '$timeout', function ($scope, $http, Upload, $timeout) {
    $scope.uploadPic = function(file) {
        var filename = file.name;
        var type = file.type;
        var query = {
            filename: filename,
            type: type
        };
        $http.post('/signing', query)
            .success(function(result) {
                Upload.upload({
                    url: result.url, //s3Url
                    transformRequest: function(data, headersGetter) {
                        var headers = headersGetter();
                        delete headers.Authorization;
                        return data;
                    },
                    fields: result.fields, //credentials
                    method: 'POST',
                    file: file
                }).progress(function(evt) {
                    console.log('progress: ' + parseInt(100.0 * evt.loaded / evt.total));
                }).success(function(data, status, headers, config) {
                    // file is uploaded successfully
                    console.log('file ' + config.file.name + 'is uploaded successfully. Response: ' + data);
                }).error(function() {

                });
            })
            .error(function(data, status, headers, config) {
                // called asynchronously if an error occurs
                // or server returns response with an error status.
        });
    };
}]);

解决方案

The example contains something I would consider an error of oversimplification.

var s3Url = 'https://' + aws.bucket + '.s3-' + aws.region + '.amazonaws.com';

This works much of the time, but it is not a consistently valid way of crafting a URL to an object in S3.

It breaks in at least two cases, one of which is the one you've encountered.

The endpoint for the US Standard region of S3, which is located in the us-east-1 region of AWS, is not s3-us-east-1.amazonaws.com, as it would be if it used the same format for all other regions. For what appear to be legacy/evolutionary reasons, it is simply s3.amazonaws.com but can also be written s3-external-1.amazonaws.com. (Remember, S3 has been around for almost ten years as of this writing, and the service has expanded and evolved, while maintaining backwards compatibiliy -- a noteworthy feat, but bound to result in some conventions that seen confusing at first glance.)

However, all buckets -- including those not in us-east-1 -- but excluding those that would break the above code for the second reason (which I haven't gotten to yet) -- can be addressed simply as bucket-name.s3.amazonaws.com -- if you think about the hierarchical nature of DNS, you can see how this might work: S3, within a few minutes after a bucket is created, remaps that specific hostname, in DNS, to send the request to the correct regional S3 endpoint.

So the + '.s3-' + aws.region + should work if written, simply, + '.s3' +.

...unless, of course, you have created a bucket with dots in its name. In this case, you will have a problem with https (this is problem #2, alluded to above), because a bucket with dots in the name will not match the wildcard SSL (TLS) certificate presented by S3 (a design limitation in SSL wildcard certificates, not S3 itself).

If this is an issue, and using a bucket with no dots in the name is undesirable for some reason, your URLs must be crafted in what's called path-style format. This is the alternative to virtual-style format, where the bucket name is in the hostname. Here, the bucket name is the first part of the path:

https://s3[-region].amazonaws.com/bucket.name.with.dots/key-path

...and, again, the first component is just s3 or s3-external-1 for US Standard (us-east-1)... but using this format requires you to match the region, unlike the above, where DNS handles the request routing... otherwise S3 will throw a permanent redirect error.

http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html

http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region

This is a lot of info, but hopefully useful in explaining not only what you need to do differently, but also why.

这篇关于AngularJs图片上传到S3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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