Rails:上传 dropzone、S3、carrierwave,不能在 Safari 中工作,但在 Google Chrome 中工作

Posted

技术标签:

【中文标题】Rails:上传 dropzone、S3、carrierwave,不能在 Safari 中工作,但在 Google Chrome 中工作【英文标题】:Rails: Uploading dropzone, S3, carrierwave, not working in Safari, but works in Google Chrome 【发布时间】:2016-03-16 22:17:25 【问题描述】:

我正在使用带有 S3 和载波的 dropzone。我可以通过谷歌浏览器上传图片,但我无法让它与 Safari 一起使用,这很奇怪。

这是我的表格

= nested_form_for @trip, html:  multipart: true, id: 'fileupload', class: 'directUpload', data:  'form-data' => (@s3_direct_post.fields), 'url' => @s3_direct_post.url, 'host' => URI.parse(@s3_direct_post.url).host   do |f|
  .dropzone#imageUpload
    = f.simple_fields_for :trip_images, TripImage.new, child_index: TripImage.new.object_id do |ff|
    = ff.file_field :photo, class: 'hide form-fields'
    = f.button :submit, id: "submit-data"

这是在 Trip 控制器中

def set_s3_direct_post
  @s3_direct_post = S3_BUCKET.presigned_post(key: "/uploads/temporary/#SecureRandom.uuid/$filename", success_action_status: '201', acl: 'public-read', content_type: 'image/jpeg')
end

这是 TripImage 模型

class TripImage < ActiveRecord::Base
  belongs_to :resource, :polymorphic => true
  mount_uploader :photo, PhotoUploader
  after_create :process_async

  def to_jq_upload
    
      'name' => read_attribute(:attachment_file_name),
      'size' => read_attribute(:attachment_file_size),
      'url' => attachment.url(:original),
      'thumbnail_url' => attachment.url(:thumb),
      'delete_url' => "/photos/#id",
      'delete_type' => 'DELETE'
    
  end

  private

  def process_async
    PhotoVersioningJob.set( wait: 5.seconds ).perform_later(self.id)
  end

end

这是js

$(function()
  $('.directUpload').find(".dropzone").each(function(i, elem) 
    s3ImageUpload(elem);
  );
)

function s3ImageUpload(elem)
  var fileInput    = $(elem);
  var form         = $(fileInput.parents('form:first'));
  var form_url = form.data('url');
  var form_data = form.data('form-data');
  Dropzone.options.imageUpload = 
    url: form_url,
    params: form_data,
    uploadMultiple: false,
    addRemoveLinks: true,
    removedfile: function(file)
      //some codes
    ,
    success: function(file, serverResponse, event)
      //some codes
    ,
    error: function(data)
      //some codes
    
  ;

编辑:当前 CORS 配置

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

经过测试,无法正常工作

编辑:我也有 S3 直接上传,不确定这是否也会影响它?

S3DirectUpload.config do |c|
  c.access_key_id = Rails::AWS.config['access_key_id']       # your access key id
  c.secret_access_key = Rails::AWS.config['secret_access_key']   # your secret access key
  c.bucket = Rails::AWS.config['bucket_name']              # your bucket name
  c.region = 's3'             # region prefix of your bucket url. This is _required_ for the non-default AWS region, eg. "s3-eu-west-1"
end

【问题讨论】:

我无权访问 safari,但我想请求上方的行可能包含 safari 不支持的调用。变量fileInput、form、form_url和form_data分别包含哪些数据? 在使用 chrome 时这些变量包含哪些数据? 如何在 Safari 中失败?在控制台中看到任何错误? @PabloKarlsson 所以我可以在控制台中查看,它确实在trip_images_attributes 中传递了临时 amazon aws url 参数,但我只是想知道为什么它不保存 chrome 保存的方式? INSERT INTO 是最后一步,尝试调试前面的步骤。是从 Safari 发出正确的请求,还是根本没有请求?如果是,从 Chrome 和 Safari 发送的参数有何不同? 【参考方案1】:

我最近在 Safari 上遇到了类似的问题,并发现它正在发送一个额外的 Access-Control-Request-Header,而 Chrome 没有——特别是“来源”。为了解决这个差异,我需要更新目标存储桶上的 AWS CORS 配置。

AWS Documentation on the necessity of request headers matching an allowed header config。第三个要点明确了这一要求:

预检请求的 Access-Control-Request-Headers 标头中列出的每个标头都必须与 AllowedHeader 元素匹配。

This helpful *** answer 给出了一个示例配置:

<?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>
    <AllowedHeader>x-requested-with</AllowedHeader>
  </CORSRule>
</CORSConfiguration>

以及需要添加什么才能使其在 Safari 中运行:

    <AllowedHeader>origin</AllowedHeader>

【讨论】:

我希望这能解决问题。我更新了我的问题以显示我的 CORS 配置是什么。这是它应该看起来的样子吗? 另外,我不确定它是否存在 CORS 问题?我正在查看 heroku 日志,但它没有插入数据库。这发生在 Chrome 中。 @hellomello 是的,假设 *.example.com 实际上是您的网站主机名。此外,您需要确保您没有获得飞行前响应的缓存版本,在您的情况下,该响应最多会停留 3000 秒。如果它仍然不适合您,我只能想到我们遇到的另一个问题,即尝试从 http 页面调用 https url 或相反。我不是您使用的堆栈方面的专家,但我在直接 s3 上传方面有相当多的经验。我做出这个答案的唯一原因是它的呈现方式完全相同(仅在 safari 中不工作) @hellomello 是进入 s3 存储桶的文件吗? 不,它没有被保存到存储桶中。我可以在 heroku 日志中看到表单正在生成表单参数中的亚马逊 URL,即:https://&lt;bucket-name&gt;.s3.amazon.aws.com/%2Fuploads%2Ftemporary%2Frandomnumbers.jpg,但是当我在存储桶中时,它不存在。我想它也不会保存到数据库记录中。网址是 https,我的网站是 http。

以上是关于Rails:上传 dropzone、S3、carrierwave,不能在 Safari 中工作,但在 Google Chrome 中工作的主要内容,如果未能解决你的问题,请参考以下文章

Rails 6主动存储sidekiq文件在S3上上传背景图片

使用 plupload 和 Rails 3 的 Amazon S3 分段上传

ruby 将CSV流从Rails上传到S3

Rails:回形针上传时 AWS S3 访问被拒绝错误

如何使用 Rails 和 Active Storage 实现 AWS S3 分段上传?

将 Rails 表单发布到 s3 上传的策略和签名问题