Come impedire la memorizzazione nella cache della pagina del browser in Rails


151

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

La parte principale del mio sito reagisce ai tuoi clic. Quindi, se fai clic su un link, ti ​​invierà alla destinazione e rigenera immediatamente la tua pagina.

Ma, se premi il pulsante Indietro, non vedi la nuova pagina. Sfortunatamente, non viene visualizzato senza un aggiornamento manuale; sembra che il browser lo stia memorizzando nella cache. Voglio assicurarmi che il browser non memorizzi nella cache la pagina.

Separatamente, io non voglio impostare lontano futuro date di scadenza per tutti i miei beni statici.

Qual è il modo migliore per risolvere questo? Devo risolverlo in Rails? Apache? Javascript?

Grazie per tutto il tuo aiuto, Jason


Ahimè. Nessuno di questi suggerimenti ha costretto il comportamento che sto cercando.

Forse c'è una risposta javascript? Potrei avere delle rotaie scrivere un timestamp in un commento, quindi fare controllare javascript per vedere se i tempi sono entro cinque secondi (o qualunque cosa funzioni). Se sì, allora bene, ma se no, ricaricare la pagina?

Pensi che funzionerebbe?

Grazie per tutto il vostro aiuto,

Jason

Risposte:


335

Alla fine l'ho capito: http://blog.serendeputy.com/posts/how-to-prevent-browsers-from-caching-a-page-in-rails/ inapplication_controller.rb

After Rails 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 e versioni precedenti:

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
Questo dovrebbe essere racchiuso in un "if request.xhr?" quindi viene impostato solo sugli aggiornamenti Ajax ma le pagine normali no?
Menta Partenza il

3
Hai davvero bisogno solo Cache-Control: no-storefinché il browser è conforme a HTTP 1.1. Sezione 14.9.2 Cosa può essere memorizzato da
Caches

28
Il 1 gennaio 1990 era un lunedì!
Jan Hettich,

2
Non funziona per me Ho aggiunto lo stesso codice in application_controller.rb e dopo il logout sono in grado di vedere l'ultima pagina con il pulsante Indietro. Per favore guidami dove sbaglio?
Thorin,

1
Anche questo NON memorizzerà nella cache JS e CSS nell'app rails? JS e CSS verranno caricati dal server per ogni richiesta?
furiabhavesh,

14

3
expires_nowinvia solo l' no-cacheintestazione. A seconda del browser questo potrebbe non essere sufficiente. (Ad esempio, Firefox vuole una no-storeconnessione non HTTPS: developer.mozilla.org/en/docs/Using_Firefox_1.5_caching )
Daniel Rikowski il

1
D'accordo, questa non è una soluzione valida, testata con Rails 5.2 e Chrome 77. no-storeè anche necessaria.
AndrewSouthpaw,

3

Ho usato questa linea con un certo successo nel controller. Funziona in Safari e Internet Explorer ma non l'ho visto funzionare con Firefox.

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

Per il tuo secondo punto, se usi i metodi di supporto delle rotaie come

stylesheet_link_tag

e lasciare le impostazioni predefinite sul server Web, le risorse vengono in genere memorizzate nella cache piuttosto bene.


3
1.year.agoè inutile sovraccarico. Scegli un po 'di tempo arbitrario in passato comeFri, 01 Jan 1990 00:00:00 GMT
Archonic,

6
@Archonic 1 gennaio 1990 era un lunedì!
Thomas R. Koll,

1

Il modo più pulito sarebbe scrivere un middleware Rack, che modifica l'intestazione Cache-Control in base a una logica (ad esempio, solo per application / xml mime-type). Oppure, per un approccio più brutto, ma ancora funzionante, si potrebbe cambiare la costante ActionDispatch :: Response :: DEFAULT_CACHE_CONTROL in "no-cache". Naturalmente, se è richiesto il controller e / o la granularità dell'azione, è meglio farlo nel controller.


1

Nota: non è possibile cancellare in modo condizionale la cache (come se before_filtersi chiamasse solo reset_cachese l'utente è già stato lì). Devi cancellare incondizionatamente la cache, perché il browser non farà una nuova richiesta solo per vedere se questa volta, deve ricaricare, anche se non è necessario che l'ultima volta.

Esempio:

before_filter :reset_cache, if: :user_completed_demographics?

non funzionerà per impedire agli utenti di tornare dopo che sono stati lì, poiché il browser utilizza le intestazioni della cache originale sul pulsante Indietro.

before_filter :reset_cache

funzionerà, comunque (dopo aver aggiornato la pagina e aver cancellato la cache da prima di averla aggiunta, ovviamente), poiché, alla prima richiesta, il browser otterrà il no-cache, no-store, ...e lo applicherà ai futuri caricamenti di pagina.


0

no_cache_control Gem.

Se è necessario eseguire questa operazione per tutte le risposte, ad esempio per superare un test di penetrazione (BURP, Detectify, ecc.), È possibile installare questa gemma su Rails 4+ per aggiungere le seguenti intestazioni a tutte le risposte:

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

Funziona come un fascino ed è davvero il modo giusto per applicazioni Web HTTPS sicure che richiedono l'autenticazione per fare qualsiasi cosa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.