Подтвердить что ты не робот

Как предотвратить Rails 3.1 от кеширования статических ресурсов до Rails.cache?

Я использую CloudFlare CDN в приложении Rails 3.1. Cloudflare - это CDN, работающий на уровне DNS. При первом попадании статического актива CloudFlare загружает его из вашего приложения, а затем кэширует его в своем CDN. Будущие запросы на загрузку этого ресурса из CDN вместо вашего приложения.

Проблема, с которой я столкнулась, заключается в том, что если вы установите для кеширования контроллера значение true:

config.action_controller.perform_caching = true

он позволяет использовать промежуточное ПО Rack:: Cache. Поскольку Rails устанавливает параметр управления кешем по умолчанию для статических активов, эти активы записываются в хранилище Rails.cache. В результате мой кеш-накопитель (в моем случае redis) заполняется статическими ресурсами с URL-адресом в качестве хэш-ключа.

К сожалению, я не могу отключить заголовки управления кэшем статических ресурсов, не затрагивая, как Cloudflare и браузеры моих пользователей кэшируют активы. Я не могу отключить кеширование контроллера, или я теряю кеширование страницы/действия/фрагмента. Тот же результат, если я удалю промежуточное ПО Rack:: Cache.

Есть ли у кого-нибудь другие идеи?

Обновление: я открыл билет на GitHub здесь.

4b9b3361

Ответ 1

Оригинальный плакат хотел предотвратить попадание статических активов в общий кеш Rails, из-за чего они хотели отключить Rack:: Cache. Вместо этого лучшим решением является настройка Rack:: Cache для использования отдельного кеша, чем общий кеш Rails.

Rack:: Кэш должен быть настроен по-разному для хранения объектов и мета-хранилища. Rack:: Cache имеет две разные области хранения: мета и сущности. Метастор хранит информацию высокого уровня о каждой записи кэша, включая HTTP-запрос и заголовки ответов. В этой области хранятся небольшие фрагменты данных, к которым обращаются на высокой частоте. Объект-хранилище кэширует содержимое тела ответа, которое может быть относительно большим количеством данных, хотя к нему обращаются реже, чем метастор.

В приведенной ниже конфигурации кэшируется информация метастара в memcached, но фактическая совокупность активов в файловой системе.

Использование memcached gem:

config.action_dispatch.rack_cache = {
  :metastore    => 'memcached://localhost:11211/meta',
  :entitystore  => 'file:tmp/cache/rack/body',
  :allow_reload => false
}

Использование dalli gem

config.action_dispatch.rack_cache = {
  :metastore    => Dalli::Client.new,
  :entitystore  => 'file:tmp/cache/rack/body',
  :allow_reload => false
}

Кстати, эта конфигурация является рекомендацией для Heroku: https://devcenter.heroku.com/articles/rack-cache-memcached-static-assets-rails31

Ответ 2

После большого количества экспериментов, я закончил это в моем config/application.rb:

if !Rails.env.development? && !Rails.env.test?
  config.middleware.insert_before Rack::Cache, Rack::Static, urls: [config.assets.prefix], root: 'public'
end

Что это значит, добавьте промежуточное ПО Rack:: Static промежуточного уровня перед запросами в Rack:: Cache. Средство Rack:: Static middleware обслуживает URL-адреса с соответствующим префиксом в корневом каталоге. Здесь я даю config.assets.prefix как мой префикс url, который по умолчанию равен //. Я устанавливаю корень в "общедоступный" каталог.

Запросы для этого пути:

/assets/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js

должен найти его в этом файле:

публичный/активы/JQuery-e8da439bbc8fd345e34ac57c6a216318.min.js

Это должно обслуживать любые активы непосредственно из каталога public/assets, а не удалять Rails:: Cache вообще, что не позволит ему хранить активы в кеш-кеке Rails. Это будет работать, только если вы запустите "rake assets: precompile" в процессе производства, иначе в "public/assets" не будет прекомпилированных активов.

Ответ 3

Вы можете отключить кэширование файлов конвейера активов, оставив другое кэширование с помощью:

config.assets.cache_store = :null_store

Это должно заставить Sprockets кэшировать что-либо.

Ответ 4

Еще один способ решить ту же проблему и эту проблему - использовать промежуточное ПО ActionDispatch:: Static вместо Rack:: Static:

if !Rails.env.development? && !Rails.env.test?
  config.middleware.insert_before Rack::Cache, ::ActionDispatch::Static, 'public', config.static_cache_control
end

В чем разница между Rack:: Static и ActionDispatch:: Static вы спрашиваете?

  • Rack:: Static берет массив префиксов url для проверки URL-адреса запроса. Поэтому в нашем случае он будет проверять только файлы, если путь запроса начинается с "/assets".

  • ActionDispatch:: Static будет проверять наличие файла в 'public' для каждого запроса GET/HEAD, независимо от пути.

  • Rack:: Static не проверяет файл первым, он вызывает Rack:: File.new в файле, поэтому, если он не существует, он вернет 404, он не будет передавать запрос вниз по цепочке промежуточного программного обеспечения.

  • Если ActionDispatch:: Static не находит файл по своему пути, он будет продолжать работу по цепочке промежуточного программного обеспечения стойки (остальная часть стека Rails).

В конце концов, какой бы ActionDispatch:: Static не нашел в "public", он просто переходит к стеку Rails. Таким образом, Rails в конечном итоге будет обслуживать активы, которые ActionDispatch:: Static не может найти. Это решает мою проблему с ресурсами, которые не обнаруживаются в Rack:: Cache, но она также более ресурсоемкая, поскольку каждый запрос запускает проверку файла.