Kampf gegen clientseitiges Caching in Django


69

Ich verwende die Verknüpfung render_to_response und möchte kein bestimmtes Antwortobjekt erstellen, um zusätzliche Header hinzuzufügen, um das clientseitige Caching zu verhindern.

Ich hätte gerne eine Antwort, die enthält:

  • Pragma: kein Cache
  • Cache-Kontrolle: kein Cache
  • Cache-Kontrolle: muss erneut validiert werden

Und all die anderen raffinierten Möglichkeiten, die Browser hoffentlich als Anweisungen interpretieren, um das Caching zu vermeiden.

Gibt es eine No-Cache-Middleware oder ähnliches, die den Trick mit minimalem Codeeinbruch ausführen kann?

Antworten:


96

Sie können dies mit dem Dekorator cache_control erreichen. Beispiel aus der Dokumentation :

from django.views.decorators.cache import never_cache

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

16
Um diese Arbeit auf allen Browsern (insbesondere FireFox und Opera, es funktionierte fein auf IE und Safari / Chrome) Ich musste manuell hinzufügen response["Cache-Control"] = "no-cache, no-store, must-revalidate"zusammen mit @never_cache. @never_cacheAnrufe add_never_cache_headers()und dies wiederum ruft, patch_cache_control()aber dies fügt nur hinzu Cache-Control:max-age=0, was anscheinend für diese Browser nicht ausreicht. Siehe stackoverflow.com/questions/49547/…
— AJJ

9
Nachdem ich den Django-Code etwas genauer untersucht hatte, fand ich eine sauberere Möglichkeit, diesen Header hinzuzufügen: patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True)
— AJJ

6
Ah, es gibt bereits ein offenes Ticket dafür unter code.djangoproject.com: @never_cache decorator sollte 'no-cache' & 'must-
— revalidate

1
@AJJ Ich denke, Sie haben auch verpasstresponse['Pragma'] = 'no-cache'
— Ory Band

7
Update im Jahr 2018: @never_cachewurde behoben, um auf allen Browsern zu funktionieren.
— Mathew

51

Dieser Ansatz (geringfügige Änderung der Lösung von L. De Leo) mit einer benutzerdefinierten Middleware hat sich für mich als standortweite Lösung bewährt:

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

Dies macht Gebrauch von add_never_cache_headers.


Wenn Sie dies mit UpdateCacheMiddlewareund kombinieren möchten FetchFromCacheMiddleware, um das serverseitige Caching zu aktivieren und gleichzeitig das clientseitige Caching zu deaktivieren, müssen Sie DisableClientSideCachingMiddlewarevor allem anderen Folgendes hinzufügen :

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

5
+1 für die Verwendung add_never_cache_headersanstelle des manuellen Einfügens von Headern.
— Michael Mior

Ich habe etwas basierend darauf verpackt. Es ist jetzt auf PyPI und Github verfügbar. github.com/incuna/django-never-cache-post
— meshy

Nur zur Info: Dies funktioniert nicht wirklich für Opera und das Zwischenspeichern von Seiten, da add_never_cache nur das maximale Alter auf Null setzt und O, und Opera das maximale Alter für diesen Zweck nicht zu berücksichtigen scheint. Siehe my.opera.com/yngve/blog/2007/02/27/…
— AdamC

Nicht genau, @AdamC. Wenn Sie mindestens zu Django 1.5 zurückkehren, werden add_never_cache_headersauch die Header "Expires" und "Last-Modified" auf die aktuelle Zeit gesetzt. Außerdem werden ETag-Header so eingestellt, dass das Caching verhindert wird, wenn USE_ETAGS in Ihren Einstellungen festgelegt ist. Siehe github.com/django/django/blob/master/django/utils/cache.py
— B Robster

Tolle Antwort. Ich habe eine Neufassung für django 1.10+ stackoverflow.com/a/47684405/2800876
— Zags

16

Ergänzende Antworten ergänzen. Hier ist ein Dekorateur, der zusätzliche Header hinzufügt, um das Caching zu deaktivieren:

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

Und Sie können es verwenden wie:

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

Kann jemand die Abwahl erklären? Ich frage mich, ob etwas grundlegend mit dem Code nicht stimmt, weil ich in einem Produktionssystem darauf angewiesen bin.
— Jan Wrobel

+1 Funktioniert auch für mich und ich sehe auch kein Problem. Es wäre sehr dankbar, einen Grund vom Downvoter zu hören.
— Zerm

7

Eigentlich war es einfach genug, meine eigene Middleware zu schreiben:

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

Benimmt sich immer noch nicht so, wie ich es wollte, aber der @ never_cache-Dekorator auch nicht


1
Diese Antwort auf Sicherstellen, dass eine Webseite nicht zwischengespeichert wird, ist in allen Browsern sehr detailliert: stackoverflow.com/questions/49547/…
— AJJ

5

In Bezug auf den Google Chrome-Browser (Version 34.0.1847.116 m) und die anderen Browser stellte ich fest, dass nur der @cache_controlDekorateur funktioniert. Ich benutze Django 1.6.2.

Verwenden Sie es so:

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

1
Was ist der beste Weg, um dies zu tun, wenn man klassenbasierte Ansichten verwendet?
— Hassan Baig

5

Hier ist eine Neufassung von @ Meilos Antwort für 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

5

Ich kratzte mir am Kopf, als die drei Magie metain Firefox und Safari nicht funktionierte.

<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" />

Anscheinend kann es passieren, dass einige Browser die Clientseite ignorieren meta, daher sollte dies auf der Serverseite behandelt werden.

Ich habe alle Antworten aus diesem Beitrag für meine klassenbasierten Ansichten ( django==1.11.6) ausprobiert . Aber unter Bezugnahme auf die Antworten von @Lorenzo und @Zags habe ich beschlossen, eine Middleware zu schreiben, die ich für einfach halte.

Also zu anderen guten Antworten hinzufügen,

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

Brillant. Dank dafür.
— michela
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.