2010-01-19 17 views
60

Utilizzo la scorciatoia render_to_response e non desidero creare un oggetto Response specifico per aggiungere intestazioni aggiuntive per impedire la memorizzazione nella cache sul lato client.Combattere la cache sul lato client in Django

Mi piacerebbe avere una risposta che contiene:

  • Pragma: no-cache
  • Cache-Control: no-cache
  • Cache-control: must-revalidate

E tutti gli altri modi ingegnosi che i browser potrebbero interpretare come direttive per evitare il caching.

C'è un middleware senza cache o qualcosa di simile che può fare il trucco con un'intrusione di codice minima?

risposta

79

È possibile ottenere ciò utilizzando il decoratore cache_control. Esempio dalla documentation:

from django.views.decorators.cache import never_cache 

@never_cache 
def myview(request): 
    # ... 
+15

per fare questo lavoro su tutti i browser (in particolare Firefox e Opera, ha funzionato bene su IE e Safari/Chrome) avevo bisogno di aggiungere manualmente 'risposta [" Cache -Control "] =" no-cache, no-store, must-revalidate "' insieme a '@ never_cache'. '@ never_cache' chiama' add_never_cache_headers() 'e questo a sua volta chiama' patch_cache_control() 'ma questo aggiunge solo' Cache-Control: max-age = 0', che a quanto pare non è abbastanza per questi browser. Vedi http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-cached-across-all-browsers – AJJ

+7

Dopo aver esplorato il codice django un po 'di più ho trovato un modo più pulito di aggiungere quell'intestazione: 'patch_cache_control (risposta, no_cache = True, no_store = True, must_revalidate = True)' – AJJ

+6

Ah, c'è già un ticket aperto per questo a code.djopoproject.com: [@never_cache decorator dovrebbe aggiungere 'no-cache '&' must-revalidate '] (https://code.djangoproject.com/ticket/13008) – AJJ

7

In realtà scrivere il mio middleware è stato abbastanza facile:

from django.http import HttpResponse 


class NoCacheMiddleware(object): 

    def process_response(self, request, response): 

     response['Pragma'] = 'no-cache' 
     response['Cache-Control'] = 'no-cache must-revalidate proxy-revalidate' 

     return response 

Ancora in realtà non si comportano come avrei voluto, ma così neanche il @never_cache decoratore

+1

Questa risposta a * Assicurarsi che una pagina Web non sia memorizzata nella cache, su tutti i browser * è abbastanza dettagliata: http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-cached- across-all-browsers – AJJ

42

Questo approccio (leggera modifica della soluzione di L. De Leo) con un middleware personalizzato ha funzionato bene per me come soluzione a livello di sito:

from django.utils.cache import add_never_cache_headers 

class DisableClientSideCachingMiddleware(object): 
    def process_response(self, request, response): 
     add_never_cache_headers(response) 
     return response 

Questo utilizza add_never_cache_headers.


Se si desidera combinare questo con UpdateCacheMiddleware e FetchFromCacheMiddleware, per consentire la memorizzazione nella cache lato server, mentre la disattivazione cache sul lato client, è necessario aggiungere DisableClientSideCachingMiddleware prima di ogni altra cosa, in questo modo:

MIDDLEWARE_CLASSES = (
    'custom.middleware.DisableClientSideCachingMiddleware', 
    'django.middleware.cache.UpdateCacheMiddleware', 
    # ... all other middleware ... 
    'django.middleware.cache.FetchFromCacheMiddleware', 
) 
+5

+1 per l'uso di 'add_never_cache_headers' invece di inserire manualmente le intestazioni. –

+0

Ho confezionato qualcosa basato su questo. Ora è disponibile su PyPI e github. https://github.com/incuna/django-never-cache-post – meshy

+0

Solo una fyi: questo non funziona davvero per Opera e il caching della pagina, perché add_never_cache imposta solo max-age a zero, e O, e Opera non sembra onorare la max-età per questo scopo. Vedi http://my.opera.com/yngve/blog/2007/02/27/introducing-cache-contexts-or-why-the – AdamC

13

Per integrare le risposte esistenti. Ecco un decoratore che aggiunge intestazioni aggiuntive per disabilitare la cache:

from django.views.decorators.cache import patch_cache_control 
from functools import wraps 

def never_ever_cache(decorated_function): 
    """Like Django @never_cache but sets more valid cache disabling headers. 

    @never_cache only sets Cache-Control:max-age=0 which is not 
    enough. For example, with max-axe=0 Firefox returns cached results 
    of GET calls when it is restarted. 
    """ 
    @wraps(decorated_function) 
    def wrapper(*args, **kwargs): 
     response = decorated_function(*args, **kwargs) 
     patch_cache_control(
      response, no_cache=True, no_store=True, must_revalidate=True, 
      max_age=0) 
     return response 
    return wrapper 

E lo si può utilizzare come:

class SomeView(View): 
    @method_decorator(never_ever_cache) 
    def get(self, request): 
     return HttpResponse('Hello') 
+0

Qualcuno può spiegare il voto negativo? Mi chiedo se qualcosa sia fondamentalmente sbagliato con il codice, perché io dipendo da esso in un sistema di produzione. –

+0

+1 Funziona bene anche per me e non vedo alcun problema. Ascoltare un motivo dal down-voter sarebbe molto apprezzato. – zerm

5

Per quanto riguarda il browser Google Chrome (versione 34.0.1847.116 m) e gli altri browser, Ho scoperto che funziona solo il decoratore @cache_control. Io uso Django 1.6.2.

usare in questo modo:

@cache_control(max_age=0, no_cache=True, no_store=True, must_revalidate=True) 
def view(request): 
    ... 
+0

Qual è il modo migliore per farlo quando si utilizzano le viste basate sulla classe? –

2

Ecco una riscrittura di @Meilo's answer per Django 1.10+:

from django.utils.cache import add_never_cache_headers 

class DisableClientCachingMiddleware(object): 
    def __init__(self, get_response): 
     self.get_response = get_response 

    def __call__(self, request): 
     response = self.get_response(request) 
     add_never_cache_headers(response) 
     return response 
0

stavo graffiare la mia testa quando i tre magia meta non ha funzionato in Firefox e Safari.

<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> 
<meta http-equiv="Pragma" content="no-cache" /> 
<meta http-equiv="Expires" content="0" /> 

Apparentemente può accadere perché alcuni browser ignorare il lato client meta, quindi dovrebbe essere gestita a lato server.

Ho provato tutte le risposte da questo post per le mie viste basate sulla classe (django==1.11.6). Ma riferendomi alle risposte di @Lorenzo e @Zags, ho deciso di scrivere un middleware che penso sia semplice.

Così l'aggiunta di altre buone risposte,

# middleware.py 
class DisableBrowserCacheMiddleware(object): 

    def __init__(self, get_response): 
     self.get_response = get_response 

    def __call__(self, request): 
     response = self.get_response(request) 
     response['Pragma'] = 'no-cache' 
     response['Cache-Control'] = 'no-cache, no-store, must-revalidate' 
     response['Expires'] = '0' 
     return response 

# settings.py 
MIDDLEWARE = [ 
    'myapp.middleware.DisableBrowserCacheMiddleware', 
    ... 
Problemi correlati