【问题标题】:Use CDN with carrierwave + fog in s3 + cloudfront with rails 3.1在 s3 中使用 CDN 和 carrierwave + 雾 + 使用 rails 3.1 的 cloudfront
【发布时间】:2012-04-14 22:47:19
【问题描述】:

我在我的网站中使用 fogcarrierwave。但是图像加载非常缓慢。

然后我想用 CDN 加速图片的加载。

我已按照本教程为图片创建 CDN:

http://maketecheasier.com/configure-amazon-s3-as-a-content-delivery-network/2011/06/25

我现在已经为图像部署了我的发行版,但我不知道 cdn 的效果如何。我在 initializers/fog.rb 中有下一个配置:

CarrierWave.configure do |config|
  config.fog_credentials = {
    :provider               => 'AWS',
    :aws_access_key_id      => 'key',
    :aws_secret_access_key  => 'key',
    :region                 => 'eu-west-1'
  }
  config.fog_host = "http://da33ii2cvf53u.cloudfront.net" #config.asset_host instead of config.fog_host for new fog gem versions
  config.fog_directory  = 'pin-pro'
  config.fog_public     = false
  #config.fog_attributes = {'Cache-Control' => 'max-age=315576000'} 
end 

我不知道这是否正确,但在我的本地机器上它对我来说不能正常工作。我看图片位置,和之前的路线是一样的:

https://s3-eu-west-1.amazonaws.com/pin-pro/uploads/pins/medium_610cafbe-5d43-4223-ab0e-daa4990863c4.jpg?AWSAccessKeyId=AKIAIDX34WHYKB3ZKFVA&Signature=RwQriNpiRXaTxyfYVvYjsvclUa8%3D&Expires=1333203059

如何使用 s3 和 cloudfront 将 CDN 添加到carrierwave 中的雾文件?

【问题讨论】:

  • 如果我使用该设置:fog_host,则会收到此错误:未定义方法 `fog_host=' for CarrierWave::Uploader::Base:Class 人们使用的是什么版本的carrierwave?跨度>
  • 您应该使用config.asset_host 而不是config.fog_host。我已将此问题添加到问题中。祝你好运!
  • 是的,经过一番挖掘,我注意到了 :) 谢谢。

标签: ruby-on-rails amazon-s3 cdn carrierwave


【解决方案1】:

您似乎没有将下面的行添加到您的配置中。您需要将下面的示例地址替换为您来自 Amazon 的云端地址。

来自 github README:https://github.com/jnicklas/carrierwave

“您可以选择在配置中包含您的 CDN 主机名。强烈建议这样做,因为没有它,每个请求都需要查找此信息”

config.asset_host = "http://c000000.cdn.rackspacecloud.com"

【讨论】:

    【解决方案2】:

    amazon cdn 似乎不适用于config.fog_public = false,因此只能从 s3 访问私有文件,而不能从 cdn 访问

    【讨论】:

      【解决方案3】:

      当您将 config.fog_public = false config.asset_host 设置为 CloudFront 分配时,CarrierWave 将不起作用。这已被多次记录:

      https://github.com/carrierwaveuploader/carrierwave/issues/1158 https://github.com/carrierwaveuploader/carrierwave/issues/1215

      在最近的一个项目中,我很高兴使用 CarrierWave 处理上传到 S3,但希望它在使用 Model.attribute_url 时返回签名的 CloudFront URL。我想出了以下(诚然丑陋的)解决方法,希望其他人可以从中受益或改进:

      'cloudfront-signer' gem 添加到您的项目中并按照说明进行配置。然后在 config/initializers 的新文件中添加以下对 /lib/carrierwave/uploader/url.rb 的覆盖(注意 AWS:: 的多次插入: CF::Signer.sign_url):

      module CarrierWave
            module Uploader
              module Url
                extend ActiveSupport::Concern
                include CarrierWave::Uploader::Configuration
                include CarrierWave::Utilities::Uri
      
                ##
                # === Parameters
                #
                # [Hash] optional, the query params (only AWS)
                #
                # === Returns
                #
                # [String] the location where this file is accessible via a url
                #
                def url(options = {})
                  if file.respond_to?(:url) and not file.url.blank?
                    file.method(:url).arity == 0 ? AWS::CF::Signer.sign_url(file.url) : AWS::CF::Signer.sign_url(file.url(options))
                  elsif file.respond_to?(:path)
                    path = encode_path(file.path.gsub(File.expand_path(root), ''))
      
                    if host = asset_host
                      if host.respond_to? :call
                        AWS::CF::Signer.sign_url("#{host.call(file)}#{path}")
                      else
                        AWS::CF::Signer.sign_url("#{host}#{path}")
                      end
                    else
                      AWS::CF::Signer.sign_url((base_path || "") + path)
                    end
                  end
                end
      
              end # Url
           end # Uploader
      end # CarrierWave
      

      然后通过将以下内容添加到同一文件的底部来覆盖 /lib/carrierwave/storage/fog.rb

      require "fog"
      
      module CarrierWave
        module Storage
          class Fog < Abstract
             class File
                include CarrierWave::Utilities::Uri
                def url
                   # Delete 'if statement' related to fog_public
                   public_url
                end
             end
          end
        end
      end
      

      最后,在 config/initializers/carrierwave.rb

      config.asset_host = "http://d12345678.cloudfront.net"

      config.fog_public = false

      就是这样。您现在可以使用 Model.attribute_url,它会将签名的 CloudFront URL 返回到由 CarrierWave 上传到您的 S3 存储桶的私有文件。

      【讨论】:

      • 我遵循了您的解决方案。我在 config/initializers 下创建了一个名为“carrier_wave_url.rb”的文件。我写的那个文件和你一样。但我有一个错误“未初始化的常量 CarrierWave::Uploader::Url::AWS”。我该如何解决?谢谢
      【解决方案4】:

      经过长时间的搜索和努力,我发现一个页面说 CarrierWave 不支持 CloudFront 签名的 url。 CloudFront 签名的 url 与 S3 签名的 url 不同,这让我有些困惑。一旦我弄清楚了,就很容易知道该怎么做。

      如果您使用config.fog_public = false 配置 CarrierWave,那么它将自动开始签署 S3 url,但它无法配置为使用 Fog 和我正在使用的 CarrierWave 版本中的 CloudFront 私有内容(1.0.0)。我什至尝试使用carrierwave-aws gem,但这也无济于事。

      因此,CarrierWave 会对 URL 进行签名,主机看起来像这样:

      https://my_bucket_name.s3-us-west-2.amazonaws.com/uploads/...?signature...
      

      它直接指向 S3 存储桶,但我需要它指向 CloudFront。我需要主机看起来像这样:

      https://s3.cloudfront_domain_name.com/uploads/...
      

      如果我将config.asset_host 设置为等于我的 CloudFront 位置会发生什么情况,我会得到这个(在“上传”之前带有双斜杠):

      https://s3.cloudfront_domain_name.com//uploads/...
      

      这也表明 CarrierWave 尚未设计为与 CloudFront 一起使用。希望他们会改进它。这是我的解决方法。它很丑,但它可以完成我需要的工作,而无需修改 CarrierWave 本身,因为我希望 CarrierWave 会在某个时候添加对 CloudFront 的支持。

      1. 首先我在我的 url 上进行了正则表达式查找/替换,并删除了 S3 主机部分 并放在我的 CloudFront 主机部分。 cf_url = s3_url.gsub("my_bucket_name.s3-us-west-2.amazonaws.com", "s3.cloudfront_domain_name.com")
      2. 接下来我做了另一个正则表达式查找/替换 删除字符串末尾的 S3 签名 url: non_signed_cf_url = cf_url.gsub(/\?.+/, '') 这是因为签名将不正确,因为它使用 S3 的 API 而不是 CloudFront 来签署 URL。
      3. 现在我使用 cloudfront-signer gem 自己重新签名 URL: signed_cf_url = Aws::CF::Signer.sign_url(non_signed_cf_url, :expires =&gt; 1.day.from_now)

      在 CloudFront 上提供私有内容时,您还需要注意一些其他事项:

      • 在您的路径模式的缓存行为设置中(不一定是默认模式),设置:“限制查看者访问 (使用签名 URL 或 已签名的 Cookie)”改为“是”
      • 将“受信任的签名者”设置为“自己”
      • 如果您想在 url 中使用除 CloudFront 签名之外的其他查询字符串,例如 response-content-dispositionresponse-content-type(我是能够使这些成功工作,但必须正确进行 url_encoded。)
      • 在您的 CloudFront 源设置中,设置您的访问身份并将“授予对存储桶的读取权限”设置为“是,更新存储桶策略”
      • 在您的常规分发设置中,确保“分发状态”为“已启用”并且您已将 CNAME 添加到“备用域名” (CNAME)”,如果您使用的是一个。
      • 如果使用 CNAME,请确保您的 DNS 已正确配置为指向您的 CloudFront 分配的名称。
      • 最后,一旦您设置了配置,在 AWS 更新分发版时会等待很长时间,因此您不会立即看到您的更改。在更改通过 CloudFront 传播之前,您的应用程序/网站似乎仍然损坏。这会使配置变得困难,因为如果您弄错了,您必须等待很长时间才能看到您的更改生效,并且您可能不确定发生了什么。但是通过这些设置,我能够让它为我工作。
      • 您还可以创建多个缓存路径模式,以便某些内容是私有的并且需要 CloudFront 签名的 url,而其他内容则不需要。例如,我设置了*.mp4 的路径模式,该模式需要所有 mp4 文件的签名,并将其置于默认行为之上。然后我将默认缓存行为设置为不需要签名的 url,这允许所有其他文件(例如图像)通过 CloudFront 分发公开访问。

      【讨论】:

        【解决方案5】:

        如前所述,Fog 或 carrierwave-aws 不允许从 Cloudfront 分发设置私有 S3 存储桶和公共访问。为此,您需要像这样覆盖上传器中的 url 方法:

        def url(*args)
          if file.respond_to?(:url) and not file.url.blank?
            if args
              "https://*my_cloudfront_url*/#{store_dir}/#{args.join('_').to_s}_#{identifier}"
            else
              "https://*my_cloudfront_url*/#{store_dir}/#{identifier}"
            end
          elsif current_path
            File.expand_path(current_path).gsub(File.expand_path(public), '')
          end
        end
        

        【讨论】:

          猜你喜欢
          • 2016-07-23
          • 2013-09-13
          • 1970-01-01
          • 2012-10-23
          • 2013-10-19
          • 1970-01-01
          • 2014-11-11
          • 2017-02-26
          • 1970-01-01
          相关资源
          最近更新 更多