[英]Use CDN with carrierwave + fog in s3 + cloudfront with rails 3.1
I'm using fog with carrierwave in my website.我在我的网站上使用带有carrierwave的雾。 But the images load very very slowly.
但是图像加载非常非常缓慢。
Then I want to speed up loading of images with a CDN.然后我想用 CDN 加速图像的加载。
I have followed this tutorial for create the CDN for images:我已经按照本教程为图像创建 CDN:
http://maketecheasier.com/configure-amazon-s3-as-a-content-delivery-network/2011/06/25 http://maketecheasier.com/configure-amazon-s3-as-a-content-delivery-network/2011/06/25
I have now my distribution deployed for images but I don't know how works fine the cdn.我现在已经为图像部署了我的发行版,但我不知道 cdn 是如何工作的。 I have in initializers/fog.rb the next configuration:
我在 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
I dont know if this is correct, but in my local machine it does not works fine for me.我不知道这是否正确,但在我的本地机器上它对我不起作用。 I see the image location, is the same route as before:
我看到图像位置,是和以前一样的路线:
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
How can I add a CDN to fog file in carrierwave with s3 and cloudfront?如何使用 s3 和 cloudfront 在carrierwave中将CDN添加到雾文件中?
It looks like you haven't added the line below to your config.看起来您还没有将下面的行添加到您的配置中。 You will need to replace the sample address below with your cloudfront address from Amazon.
您需要将下面的示例地址替换为您在 Amazon 的 cloudfront 地址。
From the github README: https://github.com/jnicklas/carrierwave来自 github README: https : //github.com/jnicklas/carrierwave
"You can optionally include your CDN host name in the configuration. This is highly recommended, as without it every request requires a lookup of this information" “您可以选择在配置中包含您的 CDN 主机名。强烈建议这样做,因为如果没有它,每个请求都需要查找此信息”
config.asset_host = "http://c000000.cdn.rackspacecloud.com"
CarrierWave won't work when you set config.fog_public = false and point config.asset_host to a CloudFront distribution.当您设置config.fog_public = false并将config.asset_host指向 CloudFront 分配时,CarrierWave 将不起作用。 This has been documented multiple times:
这已被多次记录:
https://github.com/carrierwaveuploader/carrierwave/issues/1158 https://github.com/carrierwaveuploader/carrierwave/issues/1215 https://github.com/carrierwaveuploader/carrierwave/issues/1158 https://github.com/carrierwaveuploader/carrierwave/issues/1215
In a recent project I was happy using CarrierWave to handle uploads to S3, but wanted it to return a signed CloudFront URL when using Model.attribute_url .在最近的一个项目中,我很高兴使用 CarrierWave 处理上传到 S3,但希望它在使用Model.attribute_url时返回一个签名的 CloudFront URL。 I came up with the following (admittedly ugly) workaround that I hope others can benefit from or improve upon:
我想出了以下(无可否认的丑陋)解决方法,我希望其他人可以从中受益或改进:
Add the 'cloudfront-signer' gem to your project and configure it per the instructions.将“cloudfront-signer” gem 添加到您的项目中并按照说明进行配置。 Then add the following override of /lib/carrierwave/uploader/url.rb in a new file in config/initializers (note the multiple insertions of AWS::CF::Signer.sign_url ):
然后在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
Then override /lib/carrierwave/storage/fog.rb by adding the following to the bottom of the same file:然后通过将以下内容添加到同一文件的底部来覆盖/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
Lastly, in config/initializers/carrierwave.rb :最后,在config/initializers/carrierwave.rb 中:
config.asset_host = " http://d12345678.cloudfront.net "
config.asset_host = " http://d12345678.cloudfront.net "
config.fog_public = false
config.fog_public = false
That's it.就是这样。 You can now use Model.attribute_url and it will return a signed CloudFront URL to a private file uploaded by CarrierWave to your S3 bucket.
您现在可以使用 Model.attribute_url,它会将签名的 CloudFront URL 返回到 CarrierWave 上传到您的 S3 存储桶的私有文件。
似乎亚马逊 cdn 不适用于config.fog_public = false
,所以私有文件只能从 s3 访问,不能从 cdn
After some searching and struggling with this for a long time I found a page that says that CarrierWave doesn't support CloudFront signed urls.经过长时间的搜索和挣扎,我发现一个页面说 CarrierWave 不支持 CloudFront 签名的 url。 CloudFront signed urls are different than S3 signed urls, which caused me some confusion.
CloudFront 签名的 url 与 S3 签名的 url 不同,这让我有些困惑。 Once I figured that out, it was a lot easier to know what to do.
一旦我明白了这一点,就更容易知道该怎么做。
If you configure CarrierWave with config.fog_public = false
then it will automatically begin signing S3 urls, but it can't be configured to work with Fog
and CloudFront private content in the version of CarrierWave I'm using (1.0.0)
.如果您使用
config.fog_public = false
配置 CarrierWave,那么它将自动开始对 S3 url 进行签名,但无法在我使用的 CarrierWave 版本(1.0.0)
中将其配置为使用Fog
和 CloudFront 私有内容。 I even tried using the carrierwave-aws
gem and that didn't help either.我什至尝试使用
carrierwave-aws
gem,但也无济于事。
So what would happen is that CarrierWave would sign the URL and the host would look something like this:那么会发生的情况是 CarrierWave 会对 URL 进行签名,而主机看起来像这样:
https://my_bucket_name.s3-us-west-2.amazonaws.com/uploads/...?signature...
That points directly to the S3 bucket, but I needed it to point to CloudFront.这直接指向 S3 存储桶,但我需要它指向 CloudFront。 I needed the host to look like this:
我需要主机看起来像这样:
https://s3.cloudfront_domain_name.com/uploads/...
And what would happen if I set config.asset_host
equal to my CloudFront location is I'd get this, (with double slashes before "uploads"):如果我将
config.asset_host
设置为等于我的 CloudFront 位置会发生什么,我会得到这个(在“上传”之前使用双斜线):
https://s3.cloudfront_domain_name.com//uploads/...
That, too, made it clear CarrierWave wasn't yet designed to be used with CloudFront.这也清楚地表明 CarrierWave 尚未设计为与 CloudFront 一起使用。 Hopefully they'll improve it.
希望他们会改进它。 This was my work-around.
这是我的解决方法。 It's ugly, but it worked to get done what I needed without needing to modify CarrierWave itself, as I hope CarrierWave will at some point add support for 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(/\\?.+/, '')
This is because the signature will be incorrect because it was using the API for S3 and not for CloudFront for signing the URL.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-signer
gem: signed_cf_url = Aws::CF::Signer.sign_url(non_signed_cf_url, :expires => 1.day.from_now)
There are a few other things you need to be aware of when serving private content on CloudFront:在 CloudFront 上提供私有内容时,您还需要注意一些其他事项:
response-content-disposition
and response-content-type
(I was able to get these to work successfully, but they have to be url_encoded properly.)response-content-disposition
和response-content-type
(I能够使这些成功工作,但它们必须正确进行 url_encoded。)*.mp4
that requires a signature for all mp4 files and placed that above the default behavior.*.mp4
的路径模式,它需要所有 mp4 文件的签名,并将其置于默认行为之上。 And then I have the default cache behavior set to NOT require signed urls, which allows all other files - such as images - to be publicly accessible through the CloudFront distribution.As mentioned before Fog or carrierwave-aws don´t allow to set private S3 Bucket and public access from a Cloudfront distribution.如前所述,Fog 或carrierwave-aws 不允许从 Cloudfront 发行版设置私有 S3 Bucket 和公共访问。 In order to do this you need to override the
url
method in your uploader like this:为此,您需要像这样覆盖上传器中的
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.