【问题标题】:Upload images to S3 doesn't work将图像上传到 S3 不起作用
【发布时间】:2016-11-27 10:55:49
【问题描述】:

我正在尝试将文件上传到 S3 而不必发送到我的服务器。我有一个端点,它为我提供签名的 S3 URL,我可以在其中发出 PUT 请求以将文件存储到我的存储桶。

我尝试在 JavaScript 方面做几件事,但没有成功。 (我没有使用亚马逊的 SDK,也不想使用,因为我正在寻找简单的文件上传,仅此而已)

这是我目前在 JavaScript 中尝试做的事情:

uploadToS3 = () => {
    let file = this.state.files[0];
    let formData = new FormData();
    formData.append('Content-Type', file.type);
    formData.append('file', file);
    let xhr = new XMLHttpRequest();
    xhr.open('put', this.signed_url, true);
    xhr.send(formData)
};

我尝试了很多选项,我更喜欢使用 fetch,因为我并不关心上传进度,因为这些只是图像。我从某个地方使用了 xhr 代码来尝试像上面那样。这些确实会进行网络调用,并且看起来应该可以工作,但实际上并没有。

会发生以下情况:在 S3 上创建了一个对象,当我转到公共 URL 时,它们被下载,当我使用图像查看器打开它们时,它们说它不是有效的 JPG。

我认为我没有正确上传。

这是我在邮递员中的做法:

请注意,我有正确的签名 URL,并且我已将二进制图像文件附加到请求中。并添加了一个标头,说明内容类型为 image/jpeg,如下所示:

当我登录 S3 并转到我的存储桶时,我可以看到一张图片,我可以转到它的公共 URL 并在浏览器中查看。这很完美,正是我想要的,现在我不知道如何在 JavaScript 上实现同样的效果。

PS:我什至尝试在邮递员上点击code,它不会为我生成文件代码。

【问题讨论】:

  • xhr.send(formData) ... 没有意义。当您PUT S3 中的文件时,您根本不使用任何表单结构,您只需发送正文。 Content-Type: 位于请求标头中,而不是正文中的表单数据中。 (对于任何其他标题也是如此)。下载您上传的文件并使用文本编辑器查看。一旦你看到你的代码实际发送到 S3 的内容,问题就会非常明显,然后 S3 会乖乖地存储并为后续请求提供服务。
  • 哇@Michael-sqlbot,我觉得自己简直太愚蠢了:D 我以为我试过了。但显然它现在有效。您可以发表您的评论作为答案,以便我接受吗?谢谢!你救了我!
  • 谢谢。按要求完成。

标签: javascript file-upload amazon-s3 fetch


【解决方案1】:

这里的问题从xhr.send(formData)开始。

当您在 S3 中 PUT 一个文件时,您根本不使用任何表单结构,您只需在请求正文中发送原始对象字节。

Content-Type: 和其他元数据位于请求标头中,而不是正文中的表单数据中。

在这种情况下,如果您下载上传的文件并使用文本编辑器查看它,一旦您看到您的代码实际发送到 S3 的内容,问题就会非常明显,然后 S3 会乖乖地存储并为后续请求提供服务.

请注意,S3 确实支持 browser-based form POST uploads,但这样做时签名过程有很大不同,需要您创建并签署一份政策文档,以便您可以将包括政策和签名在内的表格发送到浏览器并允许其他不受信任的用户上传文件 - 签名的策略声明可防止浏览器用户篡改表单并执行您不希望的操作。

【讨论】:

  • 嘿,我还有一个小问题,不知道我是否应该在这里问,$config = [ 'Bucket' => env('BUCKET'), 'ACL' => ' public-read', 'Key' => $key, 'CacheControl' => 'max-age=172800', 'Expires' => new \DateTime('+2 days'), ]; if($contentType){ $config['contentType'] = $contentType; $request = $this->s3->createPresignedRequest($this->s3->getCommand('PutObject', $config), $expiry);不考虑到期。而且我的图像不可缓存。有什么想法吗?
  • @NishchalGautam 我建议将此作为一个新问题发布。我和许多其他专家全天都会收到关于我们专业主题中所有新问题的定期通知。高质量的问题通常不会没有答案。上传文件,然后从 S3 下载它,捕获响应标头,并将其包含在您的问题中。 $expiry(如果正确传递)指定在生成对象后,您可以使用预签名 URL 上传对象多长时间,然后 URL 本身将不再允许您使用它进行上传——它与下载缓存无关。
  • cmets 中的代码应该非常有限,因为通常多行代码变得难以阅读......但它被 ` 反引号包围。请参阅stackoverflow.com/editing-helpmeta.stackexchange.com/questions/19756/how-do-comments-work 的最后一个条目,了解如何正确使用 cmets。
猜你喜欢
  • 1970-01-01
  • 2022-08-13
  • 2015-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 2014-07-13
相关资源
最近更新 更多