web-dev-qa-db-fra.com

Lutte contre la mise en cache côté client dans Django

J'utilise le raccourci render_to_response et je ne veux pas créer un objet Response spécifique pour ajouter des en-têtes supplémentaires pour empêcher la mise en cache côté client.

J'aimerais avoir une réponse qui contient:

  • Pragma: pas de cache
  • Contrôle du cache: pas de cache
  • Cache-control: must-revalidate

Et toutes les autres façons astucieuses que les navigateurs interpréteront, espérons-le, comme des directives pour éviter la mise en cache.

Existe-t-il un middleware sans cache ou quelque chose de similaire qui peut faire l'affaire avec une intrusion de code minimale?

66
Lorenzo

Vous pouvez y parvenir en utilisant le décorateur cache_control. Exemple de la documentation :

from Django.views.decorators.cache import never_cache

@never_cache
def myview(request):
   # ...
89
Kristian

Cette approche (légère modification de la solution de L. De Leo) avec un middleware personnalisé a bien fonctionné pour moi en tant que solution à l'échelle du site:

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

Cela utilise add_never_cache_headers .


Si vous souhaitez combiner cela avec UpdateCacheMiddleware et FetchFromCacheMiddleware, pour activer la mise en cache côté serveur tout en désactivant la mise en cache côté client, vous devez ajouter DisableClientSideCachingMiddleware avant tout le reste, comme ceci :

MIDDLEWARE_CLASSES = (
    'custom.middleware.DisableClientSideCachingMiddleware',
    'Django.middleware.cache.UpdateCacheMiddleware',
    # ... all other middleware ...
    'Django.middleware.cache.FetchFromCacheMiddleware',
)
45
Meilo

Pour compléter les réponses existantes. Voici un décorateur qui ajoute des en-têtes supplémentaires pour désactiver la mise en 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

Et vous pouvez l'utiliser comme:

class SomeView(View):
    @method_decorator(never_ever_cache)
    def get(self, request):
        return HttpResponse('Hello')
14
Jan Wrobel

En fait, écrire mon propre middleware était assez simple:

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

Ne se comporte toujours pas vraiment comme je le voulais, mais le décorateur @never_cache non plus

7
Lorenzo

En ce qui concerne le navigateur Google Chrome (version 34.0.1847.116 m) et les autres navigateurs, j'ai constaté que seul le @cache_control le décorateur travaille. J'utilise Django 1.6.2.

Utilisez-le comme ceci:

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

Voici une réécriture de @ Meilo's answer for 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
2
Zags

Je me grattais la tête lorsque les trois magie meta ne fonctionnaient pas dans Firefox et 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" />

Apparemment, cela peut se produire car certains navigateurs ignoreront le côté client meta, il doit donc être géré côté serveur.

J'ai essayé toutes les réponses de ce post pour mes vues basées sur la classe (Django==1.11.6). Mais en me référant aux réponses de @Lorenzo et @Zags, j'ai décidé d'écrire un middleware qui je pense est simple.

Donc, en ajoutant d'autres bonnes réponses,

# 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',
    ...
2
Hussain