[英]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 的支持。
cf_url = s3_url.gsub("my_bucket_name.s3-us-west-2.amazonaws.com", "s3.cloudfront_domain_name.com")
non_signed_cf_url = cf_url.gsub(/\\?.+/, '')
這是因為簽名將不正確,因為它使用的是用於 S3 而非 CloudFront 的 API 用於簽署 URL。cloudfront-signer
gem: signed_cf_url = Aws::CF::Signer.sign_url(non_signed_cf_url, :expires => 1.day.from_now)
在 CloudFront 上提供私有內容時,您還需要注意一些其他事項:
response-content-disposition
和response-content-type
(I能夠使這些成功工作,但它們必須正確進行 url_encoded。)*.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.