直接(和简单!)AJAX从(AngularJS)单页应用程序上传到AWS S3

前端之家收集整理的这篇文章主要介绍了直接(和简单!)AJAX从(AngularJS)单页应用程序上传到AWS S3前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我知道上传到AWS S3有很多覆盖.不过,我一直在努力工作大概24个小时,而且还没有找到符合我情况的答案.

我想做什么

直接从我的客户端将文件上传到AWS S3到我的S3桶.情况是:

>这是一个单页面应用程序,所以上传请求必须在AJAX
>我的服务器和我的客户端不在同一个域上
> S3桶是最新的(法兰克福),一些签名生成库不工作(见下文)
>客户端在AngularJS
>服务器是在ExpressJS

我试过了

> Heroku’s article直接上传到S3.不符合我的客户端/服务器配置(加上它真的不适合和Angular)
>现成的指令,如ng-s3upload.不起作用,因为它们的签名生成算法不被最近的s3桶接受.
>在this article(使用FormData和Angular的$http)上手动创建客户端上的文件上传指令和逻辑.它包括从服务器上的AWS(和该部分工作)获取一个签名的URL,然后将AJAX上传到该URL.它失败了一些神秘的CORS相关的消息(虽然我在Heroku设置了一个CORS配置)

看来我面临着两个困难:在我的单页应用程序中有一个文件输入,并获得AWS的工作流程.

我正在寻找的解决方

如果可能的话,我想避免“全部包含”的解决方案来管理整个过程,同时隐藏所有的复杂性,使其很难适应特殊情况.我宁愿有一个简单的解释,分解所涉及的各个组件之间的数据流,即使它需要更多的管道从我.

我终于管理了要点是:

>放开Angular的$http,并使用本机XMLHttpRequest.
>使用AWS SDK的getSignedUrl功能,而不是像许多库一样实现我自己的签名生成工作流.
>将AWS配置设置为使用正确的签名版本(在写作时为v4)和区域(在法兰克福的情况下为“eu-central-1”).

以下是我所做的一步一步的指导;它在服务器上使用AngularJS和NodeJS,但是应该很容易适应其他堆栈,特别是因为它处理最病态的情况(SPA在不同的域中,服务器,最近有一个桶)写作区域).

工作流汇总

>用户在浏览器中选择一个文件;您的JavaScript保持引用.
>客户端向您的服务器发送请求以获取签名的上传URL.
>您的服务器选择要放入存储桶中的对象的名称(确保避免名称冲突!).
>服务器使用AWS SDK获取对象的签名URL,并将其发送回客户端.这涉及对象的名称和AWS凭据.
>给定文件和签名的URL,客户端直接向您的S3 Bucket发送PUT请求.

在你开始之前

确保:

>您的服务器具有AWS SDK
>您的服务器具有适用于您的存储桶的适当访问权限的AWS凭据
>您的S3存储桶为您的客户端提供了正确的CORS配置.

步骤1:设置一个SPA友好的文件上传表单/小部件.

所有重要的是拥有一个工作流程,最终可以让您对File对象进行编程访问,而无需上传它.

在我的情况下,我使用了优秀的angular-file-upload库的ng-file-select和ng-file-drop指令.但是还有其他的方法(例如参见this post).

请注意,您可以访问文件对象中的有用信息,如file.name,file.type等.

步骤2:获取服务器上文件的签名URL

在您的服务器上,您可以使用AWS SDK获取一个安全的临时URL,从其他地方(如您的前端)将文件从PUT中删除.

在NodeJS中,我这样做:

// ---------------------------------
// some initial configuration
var aws = require('aws-sdk');

aws.config.update({
  accessKeyId: process.env.AWS_ACCESS_KEY,secretAccessKey: process.env.AWS_SECRET_KEY,signatureVersion: 'v4',region: 'eu-central-1'
});

// ---------------------------------
// now say you want fetch a URL for an object named `objectName`
var s3 = new aws.S3();
var s3_params = {
  Bucket: MY_BUCKET_NAME,Key: objectName,Expires: 60,ACL: 'public-read'
};
s3.getSignedUrl('putObject',s3_params,function (err,signedUrl) {
  // send signedUrl back to client
  // [...]
});

您可能想知道要获取对象的URL(通常是图像).为此,我只是从URL中删除查询字符串:

var url = require('url');
// ...
var parsedUrl = url.parse(signedUrl);
parsedUrl.search = null;
var objectUrl = url.format(parsedUrl);

步骤3:从客户端发送PUT请求

现在您的客户端具有您的File对象和已签名的URL,它可以将PUT请求发送到S3.在Angular案例中我的建议是使用XMLHttpRequest而不是$http服务:

var signedUrl,file;
// ...
var d_completed = $q.defer(); // since I'm working with Angular,I use $q for asynchronous control flow,but it's not mandatory
var xhr = new XMLHttpRequest();
xhr.file = file; // not necessary if you create scopes like this

xhr.onreadystatechange = function(e) {
  if ( 4 == this.readyState ) {
    // done uploading! HURRAY!
    d_completed.resolve(true);
  }
};
xhr.open('PUT',signedUrl,true);
xhr.setRequestHeader("Content-Type","application/octet-stream");
xhr.send(file);

致谢

我要感谢emil10001Will Webberley,他的出版物对我来说非常有价值.

猜你在找的Ajax相关文章