在Django中对抗客户端缓存


69

我正在使用render_to_response快捷方式,并且不想制作特定的Response对象来添加其他标头,以防止客户端缓存。

我想要一个包含以下内容的回复:

  • 语法:无缓存
  • 缓存控制:无缓存
  • 缓存控制:必须重新验证

浏览器希望将所有其他巧妙的方式解释为指令以避免缓存。

是否有没有缓存的中间件或类似的东西可以以最少的代码入侵来解决问题?

Answers:


96

您可以使用cache_control装饰器实现此目的。文档中的示例:

from django.views.decorators.cache import never_cache

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

16
为了在所有浏览器(特别是FireFox和Opera)上都可以正常使用,我需要手动将response["Cache-Control"] = "no-cache, no-store, must-revalidate"和一起添加@never_cache@never_cache调用add_never_cache_headers(),然后依次调用,patch_cache_control()但这只会添加Cache-Control:max-age=0,显然对于这些浏览器来说还不够。见 stackoverflow.com/questions/49547/...
AJJ

9
在探究了django代码后,我发现了添加该标头的更patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True)
简洁

6
啊,已经有一个开放的票在这code.djangoproject.com:@never_cache装饰应该加上“无缓存”和“必须重新验证”
AJJ

1
@AJJ我想你也很想念response['Pragma'] = 'no-cache'
Ory Band

7
2018年更新:@never_cache已修复为可在所有浏览器上使用。
马修

51

这种方法(使用L. De Leo的解决方案的轻微修改)与定制的中间件一起,对于我来说,作为站点范围的解决方案非常有效:

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

这利用add_never_cache_headers


如果要将其与UpdateCacheMiddleware和结合使用FetchFromCacheMiddleware,以在禁用客户端缓存的同时启用服务器端缓存,则需要先添加DisableClientSideCachingMiddleware其他内容,如下所示:

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

5
+1用于使用add_never_cache_headers而不是手动插入标头。
Michael

我已经基于此打包了一些东西。现在可以在PyPI和github上使用。github.com/incuna/django-never-cache-post
网状

只是一个错误:这对于Opera和页面缓存实际上并不起作用,因为add_never_cache只是将max-age设置为零,将O设置为0,而Opera似乎并没有为此目的遵守max-age。见my.opera.com/yngve/blog/2007/02/27/...
AdamC

不完全是@AdamC。至少回到Django 1.5,add_never_cache_headers还将Expires和Last-Modified标头设置为当前时间。如果在您的设置中设置了USE_ETAGS,它还将设置ETag标头避免缓存。见github.com/django/django/blob/master/django/utils/cache.py
B Robster 2015年

很棒的答案。我发布了针对django 1.10+ stackoverflow.com/a/47684405/2800876
Zags

16

补充现有答案。这是一个装饰器,它添加了其他标头以禁用缓存:

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

您可以像这样使用它:

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

有人可以解释否决票吗?我想知道代码是否根本上有问题,因为我在生产系统中依赖它。
Jan Wrobel

+1对我也很好,我也看不到任何问题。听到下降者的一个理由将不胜感激。
zerm 2013年

7

实际上,编写自己的中间件很容易:

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

仍然没有真正表现出我想要的行为,但是@never_cache装饰器也没有


1
这个答案对确保网页没有被缓存,在所有浏览器是相当详细:stackoverflow.com/questions/49547/...
AJJ

5

关于Google Chrome浏览器(版本34.0.1847.116 m)和其他浏览器,我发现只有@cache_control装饰器在工作。我使用Django 1.6.2。

像这样使用它:

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

1
使用基于类的视图时执行此操作的最佳方法是什么?
哈桑·拜格,

5

这是@Meilo对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

当这三个魔术meta在Firefox和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" />

显然有可能发生这种情况,因为某些浏览器会忽略客户端meta,因此应在服务器端进行处理。

我针对基于班级的观点(django==1.11.6)尝试了本帖子中的所有答案。但是,参考@Lorenzo和@Zags的答案,我决定编写一种我认为很简单的中间件。

因此,除了其他好的答案之外,

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

辉煌。感谢那。
米歇拉
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.