簡體   English   中英

將 CDN 與載波 + 霧在 s3 + Cloudfront 與 Rails 3.1 一起使用

[英]Use CDN with carrierwave + fog in s3 + cloudfront with rails 3.1

我在我的網站上使用帶有carrierwave的 但是圖像加載非常非常緩慢。

然后我想用 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 在carrierwave中將CDN添加到霧文件中?

看起來您還沒有將下面的行添加到您的配置中。 您需要將下面的示例地址替換為您在 Amazon 的 cloudfront 地址。

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

“您可以選擇在配置中包含您的 CDN 主機名。強烈建議這樣做,因為如果沒有它,每個請求都需要查找此信息”

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

當您設置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 存儲桶的私有文件。

似乎亞馬遜 cdn 不適用於config.fog_public = false ,所以私有文件只能從 s3 訪問,不能從 cdn

經過長時間的搜索和掙扎,我發現一個頁面說 CarrierWave 不支持 CloudFront 簽名的 url。 CloudFront 簽名的 url 與 S3 簽名的 url 不同,這讓我有些困惑。 一旦我明白了這一點,就更容易知道該怎么做。

如果您使用config.fog_public = false配置 CarrierWave,那么它將自動開始對 S3 url 進行簽名,但無法在我使用的 CarrierWave 版本(1.0.0)中將其配置為使用Fog和 CloudFront 私有內容。 我什至嘗試使用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 而非 CloudFront 的 API 用於簽署 URL。
  3. 現在我自己重新簽名 URL,使用cloudfront-signer gem: signed_cf_url = Aws::CF::Signer.sign_url(non_signed_cf_url, :expires => 1.day.from_now)

在 CloudFront 上提供私有內容時,您還需要注意一些其他事項:

  • 在路徑模式的緩存行為設置(不一定是默認設置)中,將:“限制查看者訪問(使用簽名 URL 或簽名 Cookie)”設置為“是”
  • 將“可信簽名者”設置為“自我”
  • 如果您想在 url 中使用比 CloudFront 簽名更多的其他查詢字符串,例如response-content-dispositionresponse-content-type (I能夠使這些成功工作,但它們必須正確進行 url_encoded。)
  • 在您的 CloudFront Origin Settings 中,設置您的訪問身份並將“Grant Read Permissions on Bucket”設置為“Yes, Update Bucket Policy”
  • 在您的常規分發設置中,確保“分發狀態”為“已啟用”,並且如果您正在使用 CNAME,請確保已將 CNAME 添加到“備用域名 (CNAME)”。
  • 如果使用 CNAME,請確保您的 DNS 已正確配置以將其指向您的 CloudFront 分配的名稱。
  • 最后,一旦您設置了配置,AWS 更新分配需要等待很長時間,因此您不會立即看到您的更改發生。 在更改通過 CloudFront 傳播之前,您的應用程序/網站似乎仍然損壞。 這會使配置變得困難,因為如果您弄錯了,您必須等待很長時間才能看到更改生效,而且您可能不確定發生了什么。 但是通過這些設置,我能夠讓它為我工作。
  • 您還可以創建多個緩存路徑模式,以便某些內容是私有的並且需要 CloudFront 簽名的 url,而其他內容則不需要。 例如,我設置了一個*.mp4的路徑模式,它需要所有 mp4 文件的簽名,並將其置於默認行為之上。 然后我將默認緩存行為設置為不需要簽名的 url,這允許所有其他文件 - 例如圖像 - 可以通過 CloudFront 分發公開訪問。

如前所述,Fog 或carrierwave-aws 不允許從 Cloudfront 發行版設置私有 S3 Bucket 和公共訪問。 為此,您需要像這樣覆蓋上傳器中的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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM