Rails 6 Amazon S3 错误 POST 403(禁止)使用 s3_direct_upload gem

Rails 6 Amazon S3 Error POST 403 (Forbidden) using s3_direct_upload gem

我已经将 2 个使用旧版本 Rails v3.2 和 4.2 的应用程序重写为当前的 Rails 6.1.4.1 在这两个应用程序中,除了图片之外,我的一切都正常工作上传。起初我无法让 s3_direct_upload 正常工作。现在它似乎可以正常工作,我开始显示进度条,但出现了该死的 POST 403(禁止)错误(错误中间有 URL)。 s3_direct_upload gem 基本上只是把 jQuery-file-upload gem 封装起来,看源码后更容易实现。

https://github.com/waynehoover/s3_direct_upload

我的情况奇怪的是,我知道这不是 CORS 问题,因为我使用的是完全相同的存储桶、密钥以及目前仍在 Heroku 上运行的这些应用程序的原始版本中的所有内容.代码几乎相同,唯一的变化是 Rails 的新版本。两者都给我完全相同的错误。在这两个应用程序中,我都可以很好地查看图片。 IT 可以访问具有相同密钥 ID 和其他所有内容的存储桶。

然后我尝试制作了一个示例应用程序,它使用 jQuery-file-upload gem(与 s3_direct_upload gem 分开),因为我想验证如果是 s3_direct_upload gem 导致了问题,或者是 jQuery-file-upload gem 导致了问题。

https://github.com/railscasts/383-uploading-to-amazon-s3/tree/master/gallery-jquery-fileupload

我制作了这个应用程序的 Rails 6 版本,并且一切正常,令我恐惧的是,它给了我完全相同的问题,POST 403(禁止)错误。
我想出了如何在应用程序的 JavaScript 部分启用 colsole.log 并让它转储错误。

这是来自控制台的完整错误。 (我将 MYBUCKET 放在我的存储桶名称所在的大写字母中)

VM3692:1 POST https://MYBUCKET.s3.amazonaws.com/ 403 (Forbidden)
(anonymous) @ VM3692:1
XMLHttpRequest.send @ includes.js?v=35a79b300ab5afa978cb59af0b05e059:839
send @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:10254
ajax @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:9738
send @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:13646
_onSend @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:13708
(anonymous) @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:12078
data.submit @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:13414
add @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:14375
_trigger @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:12478
(anonymous) @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:13777
each @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:370
_onAdd @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:13770
(anonymous) @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:12078
(anonymous) @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:13975
fire @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:3232
add @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:3291
always @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:3400
_onChange @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:13965
(anonymous) @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:12078
handlerProxy @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:12389
dispatch @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:5226
elemData.handle @ application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:4878
application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:14438 Upload failed:
application-c24f8496b74e37ed951b517eb53daac49c7c8be5d2307e5af5413626d42a478c.js:14439 
abort: ƒ ()
add: ƒ (e, data)
autoUpload: true
bitrate: 1645390.4761904762
bitrateInterval: 500
blob: null
cache: false
contentType: false
context: jQuery.fn.init [div#upload_eq38hayegan.upload]
create: null
data: FormData {}
disabled: false
done: ƒ (e, data)
dropZone: jQuery.fn.init [div#before-pictures-dropzone.well.dropzone, context: document, selector: '#before-pictures-dropzone']
errorThrown: "Forbidden"
fail: ƒ (e, data)
fileInput: jQuery.fn.init [input#before_photo, context: input#before_photo]
fileInputClone: jQuery.fn.init [input#before_photo, prevObject: jQuery.fn.init(1), context: input#before_photo]
files: [File]
forceIframeTransport: false
form: jQuery.fn.init [form#attachment_before, context: form#attachment_before]
formAcceptCharset: "UTF-8"
formData: ƒ (form)
headers: {}
i18n: ƒ (message, context)
jqXHR: {readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
limitMultiFileUploadSizeOverhead: 512
loaded: 86383
messages: {uploadedBytes: 'Uploaded bytes exceed file size'}
multipart: true
originalFiles: [File]
paramName: ['file']
pasteZone: jQuery.fn.init {}
process: ƒ (resolveFunc, rejectFunc)
processData: false
processing: ƒ ()
progress: ƒ ()
progressInterval: 100
recalculateProgress: true
replaceFileInput: true
response: ƒ ()
sequentialUploads: false
singleFileUploads: true
start: ƒ (e)
state: ƒ ()
submit: ƒ ()
textStatus: "error"
timeout: 0
total: 86383
type: "POST"
uploadedBytes: 0
url: "https://MYBUCKET.s3.amazonaws.com/"
xhr: ƒ ()
_bitrateTimer: {_super: undefined, _superApply: undefined, timestamp: 1634768499443, loaded: 86383, bitrate: 1645390.4761904762, …}
_progress: {loaded: 86383, total: 86383, bitrate: 1645390.4761904762}
_response: {jqXHR: {…}, textStatus: 'error', errorThrown: 'Forbidden'}
_time: 1634768499443
[[Prototype]]: Object

我很想知道如何让这些应用程序在 Rails 6 中正常运行(如果可能的话)。如果不是,我什至愿意听到最好使用现有回形针和 amazon-sdk-v1 或 amazon-sdk gems 的潜在替代品。我只需要其他东西来替换上传功能,但甚至愿意考虑可以完成上述所有功能的东西。这对我来说只是一条更加艰难的道路,因为我在这方面还是一个初学者。

我已经尝试过旧版本,因为原始应用程序是用 amazon-sdk-v1 和 amazon-sdk(版本 3)编写的。必须更新一些项目才能使 v3 正常工作。在这两种情况下,我都能很好地看到图片,只是无法上传。问题似乎与 POST / 上传功能以及 s3_direct_upload 或 jQuery-file-upload gems 无关。我假设我还需要做一些其他事情才能让这些应用程序与 Rails 6 一起工作,我只是不知道它是什么。

如果有人想看任何具体的内容,请告诉我,如果不展示我知道人们不喜欢的所有内容,我不确定该展示什么。

如有任何帮助,我们将不胜感激, 谢谢你, 斯科特

问题出在 s3_direct_upload 创建上传表单的过程中。它正在使用 $utf8 向表单中添加一个部分,这显然在某些时候不再被允许。在 s3_direct_upload gem v0.1.7 中 /app/lib/form_helper.rb 在方法 def policy_data 方法中必须从方法中删除此行:

["starts-with", "$utf8", ""],

一旦您从 gem 的本地副本中删除了它,POST 错误就会消失,并且它会成功上传到 Amazon S3。然而,这除了您的本地副本外没有任何帮助,您显然不能将该更改推送到 Heroku 或其他任何地方。

在进一步检查 s3_direct_upload GIT 存储库后,我发现你是否将最新版本作为插件而不是作为 gem 某个人在这个过程中发现了政策错误并修复了它,他们也添加了一些更多的功能,但由于这个原因,您还必须向您的 file_field_tag 添加一个额外的选项。

您可以通过以下方式为 Rails 6

提取 GEM 的工作版本
gem 's3_direct_upload', github: 'waynehoover/s3_direct_upload', ref: '6f6decc75fdf89888d7f729fc89f78e90d91cece'

如果您将其放入 gem 文件并使用 bundle install,它将转至 GIT 并将所有最新更改提取到 GEM。如果您去寻找 gem 的本地副本,它最终会把它放在一个稍微不同的地方。 它被置于:

C:\Ruby27-x64\lib\ruby\gems.7.0\bundler\gems

而不是:

C:\Ruby27-x64\lib\ruby\gems.7.0\gems

最后,当你拉取这个最新版本时,你必须添加

data: { url: s3_uploader_url }

到你的 file_field_tag 结尾,例如我的是:

= file_field_tag(:file, id: "before_photo", multiple: true, data: { url: s3_uploader_url })

如果您拉取最新版本并添加数据:{ url: s3_uploader_url } 到您 file_field_tag 的末尾,您的 s3_direct_upload 应该开始正常工作.