В этом посте я писал о том, как мы делаем упаковку активов с помощью Rails, как мы Jammit и переносим их на S3 . С тех пор у нас было несколько сюрпризов, один из которых был связан со сжатыми активами.
Если браузер отправляет заголовок Accept-Encoding: gzip для ресурса, который имеет как несжатую, так и сжатую копию (например, client.js и client.js.gz ), сервер может ответить сжатой версией файла вместе с исходный Content-Type (например, text / css ) и Content-Encoding: gzipзаголовки. Это называется согласованием контента. К сожалению, у S3 очень плохие навыки ведения переговоров. CloudFront CDN работает лучше, но только если сервер его поддерживает. Таким образом, размещение CloudFront перед S3 дает тот же эффект, и Amazon рекомендует использовать пользовательский сервер происхождения (причудливое слово для другого веб-сервера), отличный от S3, если вы хотите включить согласование содержимого. Мы не хотели бы обслуживать статические активы от Heroku, потому что это требует проверки их в системе контроля версий. И мы не хотели бы добавлять веб-сервер, который мы должны поддерживать, — слишком много инфраструктуры, если умножить на количество разработчиков.
Решение, как обычно, состоит в том, чтобы
рельсы. Мы расскажем нашему приложению Rails, что нужно обслуживать сжатый файл, если браузер включает правильные заголовки, отображая URL-адрес сжатой версии.
обезопасить
В Rails 3.0 (ваш пробег будет варьироваться для 3.1) пути к ресурсам записываются с помощью ActionView :: Helpers :: AssetTagHelper ‘s path_to_javascript и path_to_stylesheet . Мы можем выяснить возможности браузера, изучив request.env [‘HTTP_ACCEPT_ENCODING’] и переписав эти URL по своему вкусу.
module ActionView module Helpers module AssetTagHelper def accept_encoding?(encoding) (request.env['HTTP_ACCEPT_ENCODING'] || '').split(',').include?(encoding) end def rewrite_path_to_gzip?(source) (! config.asset_host.blank?) and (source =~ /assets\//) and accept_encoding?('gzip') end def path_to_javascript(source) source = rewrite_path_to_gzip(source) if rewrite_path_to_gzip?(source) compute_public_path(source, 'javascripts', 'js') end def path_to_stylesheet(source) source = rewrite_path_to_gzip(source) if rewrite_path_to_gzip?(source) compute_public_path(source, 'stylesheets', 'css') end def rewrite_path_to_gzip(source) source + ".cgz" end end end
config / initializers / asset_tag_helper.rb и spec / initializers / rails / asset_tag_helper_spec.rb
Расширение .cgz заменяет расширение .gz, чтобы обойти ошибку в Safari . Rewrite_path_to_gzip? check гарантирует, что мы рендерим что-то под активы и что мы используем внешний сервер (не в разработке). Ваше состояние может быть другим.
Наконец, мы должны установить правильные заголовки кодирования содержимого при передаче ресурсов на S3. Вот мясо нашей задачи по Грабли.
File.open(entry) do |entry_file| content_options = {} content_type = MIME::Types.type_for(entry)[0] content_options['x-amz-acl'] = 'public-read' if entry.ends_with?('.gz') uncompressed_entry = entry[0..-4] entry = "#{uncompressed_entry}.cgz" content_type = MIME::Types.type_for(uncompressed_entry)[0] content_options['content-encoding'] = 'gzip' end content_options['content-type'] = content_type.to_s key = 'assets/' key += entry.slice(from.length + 1, entry.length - from.length - 1) s3i.put(to, key, entry_file, content_options) end
Обратите внимание, что Content-Type для файла .css.gz такой же, как и для файла .css ( text / css ), и что для Content-Encoding установлено значение gzip .
Чтобы убедиться, что ваша реализация работает, проверьте исходный код страницы и убедитесь, что вы получили ссылку .css.cgz для таблиц стилей. Затем перейдите к URL-адресу .css.cgz — он должен отображать несжатый CSS .
Для пуристов эта реализация действительно плохая. Браузер может запросить веб-страницу с Accept-Encoding: gzip , но затем запросить CSS с другого сервера без него. Я собираюсь решить, что это никогда не происходит в реальной жизни.
Источник: http://code.dblock.org/serving-compressed-rails-assets-from-s3-via-cloudfront