Jak zapobiec buforowaniu stron przeglądarki w Railsach

151

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

Główna część mojej witryny reaguje na Twoje kliknięcia. Jeśli więc klikniesz link, przekieruje Cię on do miejsca docelowego i natychmiast zregeneruje Twoją stronę.

Ale jeśli naciśniesz przycisk Wstecz, nie zobaczysz nowej strony. Niestety nie pojawia się bez ręcznego odświeżania; wygląda na to, że przeglądarka go buforuje. Chcę się upewnić, że przeglądarka nie buforuje strony.

Osobno, ja nie chcę, aby ustawić daleko przyszłych dat ważności dla wszystkich moich zasobów statycznych.

Jaki jest najlepszy sposób rozwiązania tego problemu? Czy powinienem rozwiązać ten problem w Railsach? Apache? Javascript?

Dzięki za całą twoją pomoc, Jason


Niestety. Żadna z tych sugestii nie wymusiła zachowania, którego szukam.

Może jest odpowiedź javascript? Mógłbym kazać railsom napisać znacznik czasu w komentarzu, a następnie sprawdzić javascript, aby sprawdzić, czy czasy mieszczą się w ciągu pięciu sekund (lub cokolwiek działa). Jeśli tak, to dobrze, ale jeśli nie, to ponownie załaduj stronę?

Czy myślisz, że to zadziała?

Dzięki za całą twoją pomoc,

Jason

Jason Butler
źródło

Odpowiedzi:

335

W końcu to rozgryzłem - http://blog.serendeputy.com/posts/how-to-prevent-browsers-from-caching-a-page-in-rails/ inapplication_controller.rb

Po Railsach 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 i starsze wersje:

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
Jason Butler
źródło
3
Czy powinno to być opakowane w „if request.xhr?” więc jest ustawiany tylko przy odświeżaniu Ajax, ale normalne strony nie?
MintDeparture
3
Naprawdę potrzebujesz Cache-Control: no-storetylko wtedy, gdy przeglądarka jest zgodna z HTTP 1.1. Sekcja 14.9.2 Co może być przechowywane w
skrytkach
28
1 stycznia 1990 był poniedziałek!
Jan Hettich
2
To nie działa dla mnie dodałem ten sam kod w application_controller.rb i po wylogowaniu mogę zobaczyć ostatnią stronę przyciskiem Wstecz. Proszę, prowadź mnie tam, gdzie się mylę?
Thorin
1
Czy to również NIE będzie buforować JS i CSS w aplikacji railsowej? Czy JS i CSS będą ładowane z serwera dla każdego żądania?
furiabhavesh
14

posługiwać się:

expires_now()

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

Sacre
źródło
3
expires_nowwysyła tylko no-cachenagłówek. W zależności od przeglądarki może to nie wystarczyć. (Na przykład Firefox chce no-storepołączeń innych niż HTTPS: developer.mozilla.org/en/docs/Using_Firefox_1.5_caching )
Daniel Rikowski
1
Zgoda, to nie jest poprawne rozwiązanie, przetestowane z Railsami 5.2 i Chrome 77. no-storejest również potrzebne.
AndrewSouthpaw
3

Użyłem tej linii z pewnym sukcesem w kontrolerze. Działa w Safari i Internet Explorerze, ale nie widziałem, żeby działał z Firefoksem.

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

Po drugie, jeśli używasz metod pomocniczych rails, takich jak

stylesheet_link_tag

i pozostaw domyślne ustawienia na swoim serwerze internetowym, zasoby są zwykle buforowane całkiem dobrze.

erik
źródło
3
1.year.agoto niepotrzebne obciążenie. Wystarczy wybrać dowolny czas jakiś w przeszłości jakFri, 01 Jan 1990 00:00:00 GMT
Archonic
6
@Archonic 1 stycznia 1990 był poniedziałek!
Thomas R. Koll
1

Bardziej przejrzystym sposobem byłoby napisanie oprogramowania pośredniczącego Rack, które zmienia nagłówek Cache-Control na podstawie pewnej logiki (na przykład tylko dla typu mime application / xml). Lub, dla brzydszego, ale wciąż działającego podejścia, można zmienić stałą ActionDispatch :: Response :: DEFAULT_CACHE_CONTROL na „no-cache”. Oczywiście, jeśli wymagana jest szczegółowość kontrolera i / lub akcji, lepiej zrobić to w kontrolerze.

rzymski
źródło
1

Uwaga: nie można warunkowo wyczyścić pamięci podręcznej (np. Gdy before_filterdzwoni tylko reset_cachewtedy, gdy użytkownik już tam był). Musisz bezwarunkowo wyczyścić pamięć podręczną, ponieważ przeglądarka nie wysyła nowego żądania tylko po to, aby sprawdzić, czy tym razem musi zostać ponownie załadowane, mimo że nie musiało to być ostatnim razem.

Przykład:

before_filter :reset_cache, if: :user_completed_demographics?

nie będzie działać, aby uniemożliwić użytkownikom powrót po tym, jak tam byli, ponieważ przeglądarka używa oryginalnych nagłówków pamięci podręcznej na przycisku Wstecz.

before_filter :reset_cache

zadziała jednak (oczywiście po odświeżeniu strony i wyczyszczeniu pamięci podręcznej sprzed dodania tego), ponieważ przy pierwszym żądaniu przeglądarka pobierze plik no-cache, no-store, ...i zastosuje go do przyszłych ładowań strony.

BalinKingOfMoria Przywróć CM
źródło
0

no_cache_control Klejnot.

Jeśli musisz to zrobić dla wszystkich odpowiedzi, np. Aby przejść test penetracyjny (BURP, Detectify itp.), Możesz zainstalować ten Gem na Rails 4+, aby dodać następujące nagłówki do wszystkich odpowiedzi:

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

Działa jak urok i jest naprawdę właściwą drogą do tworzenia bezpiecznych aplikacji internetowych HTTPS, które wymagają uwierzytelnienia.

Joshua Pinter
źródło