Как предотвратить кеширование страниц браузера в Rails

151

Ubuntu -> Apache -> Phusion Passenger -> Rails 2.3

Основная часть моего сайта реагирует на ваши клики. Поэтому, если вы нажмете на ссылку, она отправит вас к месту назначения и мгновенно восстановит вашу страницу.

Но, если вы нажмете кнопку «Назад», вы не увидите новую страницу. К сожалению, оно не отображается без обновления вручную; кажется, что браузер кеширует его. Я хочу убедиться, что браузер не кэширует страницу.

Отдельно я бы хочу установить даты истечения срока действия далеко в будущем для всех моих статических активов.

Какой лучший способ решить это? Должен ли я решить это в Rails? Apache? Javascript?

Спасибо за вашу помощь, Джейсон


Увы. Ни одно из этих предложений не заставило меня искать нужное поведение.

Может быть, есть ответ javascript? Я мог бы сделать так, чтобы rails записали временную метку в комментарии, а затем проверили javascript, чтобы увидеть, находятся ли времена в течение пяти секунд (или как-то работает). Если да, то хорошо, но если нет, то перезагрузите страницу?

Как вы думаете, это будет работать?

Спасибо за вашу помощь,

Джейсон

Джейсон Батлер
источник

Ответы:

335

Наконец-то понял это - http://blog.serendeuty.com/posts/how-to-prevent-browsers-from-caching-a-page-in-rails/ вapplication_controller.rb

После рельсов 5:

class ApplicationController < ActionController::Base

  before_action :set_cache_headers

  private

  def set_cache_headers
    response.headers["Cache-Control"] = "no-cache, no-store"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
  end
end

Rails 4 и более старые версии:

class ApplicationController < ActionController::Base

  before_filter :set_cache_headers

  private

  def set_cache_headers
    response.headers["Cache-Control"] = "no-cache, no-store"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
  end
end
Джейсон Батлер
источник
3
Должно ли это быть заключено в "if request.xhr?" поэтому он устанавливается только при обновлении ajax, а обычные страницы - нет?
MintDeparture
3
Вам действительно нужно, Cache-Control: no-storeпока браузер совместим с HTTP 1.1. Раздел 14.9.2. Что может
храниться в кэше
28
1 января 1990 года был понедельник!
Ян Хеттих,
2
Это не работает для меня, я добавил тот же код в application_controller.rb и после выхода из системы я могу увидеть последнюю страницу с помощью кнопки назад. Пожалуйста, ведите меня, где я не прав?
Торин
1
Это также НЕ кеширует JS и CSS в приложении rails? Будут ли JS и CSS загружаться с сервера для каждого запроса?
furiabhavesh
14

использовать:

expires_now()

http://api.rubyonrails.org/classes/ActionController/ConditionalGet.html#method-i-expires_now

Sacre
источник
3
expires_nowтолько отправляет no-cacheзаголовок. В зависимости от браузера этого может быть недостаточно. (Например, Firefox хочет no-storeдля соединений не-HTTPS: developer.mozilla.org/en/docs/Using_Firefox_1.5_caching )
Даниэль Риковски,
1
Согласитесь, это недопустимое решение, протестировано с Rails 5.2 и Chrome 77. no-storeТакже необходимо.
AndrewSouthpaw
3

Я использовал эту строку с некоторым успехом в контроллере. Он работает в Safari и Internet Explorer, но я не видел, чтобы он работал с Firefox.

response.headers["Expires"] = "#{1.year.ago}"

Во-вторых, если вы используете вспомогательные методы rails, такие как

stylesheet_link_tag

и оставьте настройки по умолчанию на вашем веб-сервере, ресурсы обычно кешируются довольно хорошо.

Erik
источник
3
1.year.agoэто ненужные накладные расходы. Просто выберите произвольное время в прошлом, напримерFri, 01 Jan 1990 00:00:00 GMT
Archonic
6
@ Archonic 1 января 1990 был понедельник!
Томас Р. Колл
1

Более чистым способом было бы написать промежуточное программное обеспечение Rack, которое изменяет заголовок Cache-Control на основе некоторой логики (например, только для application / xml mime-type). Или, для более уродливого, но все еще работающего подхода, можно изменить константу ActionDispatch :: Response :: DEFAULT_CACHE_CONTROL на 'no-cache'. Конечно, если требуется контроллер и / или гранулярность действий, лучше сделать это в контроллере.

Римский
источник
1

Замечание: вы не можете условно очистить кеш (например, если before_filterзвонит только, reset_cacheесли пользователь уже был там). Вам необходимо безоговорочно очистить кеш, потому что браузер не будет делать новый запрос, просто чтобы посмотреть, нужно ли на этот раз перезагрузить его, даже если в прошлый раз это не требовалось.

Пример:

before_filter :reset_cache, if: :user_completed_demographics?

не будет работать, чтобы предотвратить возвращение пользователей после того, как они были там, так как браузер использует оригинальные заголовки кэша на кнопке «Назад».

before_filter :reset_cache

однако будет работать (после обновления страницы и очистки кеша до того, как вы добавили это, очевидно), так как по первому запросу браузер получит no-cache, no-store, ...и применит его к будущим загрузкам страницы.

BalinKingOfMoria Восстановить CM
источник
0

no_cache_control Gem.

Если вам нужно сделать это для всех ответов, например, чтобы пройти тест на проникновение (BURP, Detectify и т. Д.), Вы можете установить этот Gem на Rails 4+, чтобы добавить следующие заголовки ко всем ответам:

Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: -1

Работает как шарм и действительно является правильным путем для создания безопасных веб-приложений HTTPS, которые требуют аутентификации, чтобы что-либо делать.

Джошуа Пинтер
источник