gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 03:41:29 24 4
gpt4 key购买 nike

我知道有很多关于上传到 AWS S3 的报道。然而,我已经为此苦苦挣扎了大约 24 小时,但我还没有找到任何适合我情况的答案。

我正在尝试做什么

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

  1. 这是一个单页应用,因此上传请求必须采用 AJAX
  2. 我的服务器和客户端不在同一域
  3. S3 存储桶是最新类型(法兰克福),某些签名生成库无法正常工作(见下文)
  4. 客户端使用 AngularJS
  5. 服务器采用 ExpressJS

我尝试过的

  • Heroku's article直接上传到S3。不适合我的客户端/服务器配置(而且它确实与 Angular 不协调)
  • 现成的指令,如 ng-s3upload 。不起作用,因为最近的 s3 存储桶不接受它们的签名生成算法。
  • 在客户端手动创建文件上传指令和逻辑,如 this article 中所示(使用 FormData 和 Angular 的 $http)。它包括从服务器上的 AWS 获取签名 URL(并且该部分有效),然后通过 AJAX 上传到该 URL。它因一些神秘的 CORS 相关消息而失败(尽管我确实在 Heroku 上设置了 CORS 配置)

我似乎面临着两个困难:拥有在我的单页应用程序中工作的文件输入,以及让 AWS 的工作流程正确。

我正在寻找的解决方案

如果可能的话,我希望避免“全包含”解决方案,这些解决方案管理整个流程,同时隐藏所有复杂性,使其难以适应特殊情况。我更愿意有一个简单的解释来分解所涉及的各个组件之间的数据流,即使它需要我进行更多的处理。

最佳答案

我终于成功了。要点是:

  1. 放弃 Angular 的 $http,而使用原生 XMLHttpRequest
  2. 使用 AWS SDK 的 getSignedUrl 功能,而不是像许多库那样实现我自己的签名生成工作流程。
  3. 将 AWS 配置设置为使用正确的签名版本(撰写本文时为 v4)和区域(对于法兰克福,为 'eu-central-1')。

下面是我所做的分步指南;它在服务器上使用 AngularJS 和 NodeJS,但应该很容易适应其他堆栈,特别是因为它处理最病态的情况(SPA 位于服务器不同的域上,最近有一个存储桶 - 在写入 - 区域)。

<小时/>

工作流程摘要

  1. 用户在浏览器中选择一个文件;你的 JavaScript 保留了对它的引用。
  2. 客户端向您的服务器发送请求以获取签名的上传 URL。
  3. 您的服务器为要放入存储桶中的对象选择一个名称(确保避免名称冲突!)。
  4. 服务器使用 AWS 开发工具包获取您的对象的签名 URL,并将其发送回客户端。这涉及对象的名称和 AWS 凭证。
  5. 根据文件和签名的 URL,客户端将 PUT 请求直接发送到您的 S3 存储桶。
<小时/>

开始之前

确保:

  • 您的服务器具有 AWS 开发工具包
  • 您的服务器拥有 AWS 凭证,并对您的存储桶具有适当的访问权限
  • 您的 S3 存储桶具有适合您的客户端的 CORS 配置。

第 1 步:设置 SPA 友好的文件上传表单/小部件。

最重要的是拥有一个工作流程,最终使您能够以编程方式访问 File 对象 - 无需上传它。

就我而言,我使用了优秀的 angular-file-uploadng-file-selectng-file-drop 指令。图书馆。但还有其他方法可以做到这一点(例如,请参阅this post。)。

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

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

在您的服务器上,您可以使用 AWS 开发工具包获取安全的临时 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 ,他的出版物对于本期的我来说非常有值(value)。

关于ajax - 从 (AngularJS) 单页应用程序直接(且简单!)AJAX 上传到 AWS S3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28739965/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com