在Django中对抗客户端缓存

时间:2022-02-27 15:37:51

I'm using the render_to_response shortcut and don't want to craft a specific Response object to add additional headers to prevent client-side caching.

我正在使用render_to_response快捷方式,并且不希望设计一个特定的响应对象来添加额外的头来防止客户端缓存。

I'd like to have a response that contains:

我想回答如下问题:

  • Pragma: no-cache
  • 编译指示:no - cache
  • Cache-control : no-cache
  • cache - control:no - cache
  • Cache-control: must-revalidate
  • cache - control:must-revalidate

And all the other nifty ways that browsers will hopefully interpret as directives to avoid caching.

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

Is there a no-cache middleware or something similar that can do the trick with minimal code intrusion?

是否有一个无缓存的中间件或类似的东西可以在最少的代码入侵情况下完成这个任务?

7 个解决方案

#1


82  

You can achieve this using the cache_control decorator. Example from the documentation:

您可以使用cache_control decorator实现这一点。文档的例子:

from django.views.decorators.cache import never_cache

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

#2


44  

This approach (slight modification of L. De Leo's solution) with a custom middleware has worked well for me as a site wide solution:

这种方法(稍微修改了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

This makes use of add_never_cache_headers.

这就使用了add_never_cache_header。


If you want to combine this with UpdateCacheMiddleware and FetchFromCacheMiddleware, to enable server-side caching while disabling client-side caching, you need to add DisableClientSideCachingMiddleware before everything else, like this:

如果您想要将它与updatecachemileware和fetchfromcachemileware结合起来,以便在禁用客户端缓存的同时启用服务器端缓存,那么您需要在一切之前添加DisableClientSideCachingMiddleware中间件,如下所示:

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

#3


14  

To supplement existing answers. Here is a decorator that adds additional headers to disable caching:

补充现有的答案。这里有一个decorator,它添加了附加的header来禁用缓存:

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

And you can use it like:

你可以这样使用:

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

#4


7  

Actually writing my own middleware was easy enough:

实际上,编写自己的中间件非常简单:

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

Still doesn't really behave like i wanted but so neither does the @never_cache decorator

仍然不像我想的那样,但是@never_cache decorator也是如此

#5


5  

Regarding the Google Chrome browser (Version 34.0.1847.116 m) and the other browsers, I found that only the @cache_control decorator is working. I use Django 1.6.2.

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

Use it like this:

使用它是这样的:

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

#6


2  

Here is a rewrite of @Meilo's answer for Django 1.10+:

下面重写@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

#7


0  

I was scratching my head when the three magic meta didn't work in Firefox and Safari.

当这三个神奇的元数据在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" />

Apparently it can happen because some browsers will ignore the client side meta, so it should be handled at server side.

显然,这可能发生,因为一些浏览器会忽略客户端元数据,所以应该在服务器端处理它。

I tried all the answers from this post for my class based views (django==1.11.6). But referring to answers from @Lorenzo and @Zags, I decided to write a middleware what I think is a simple one.

我为基于类的视图尝试了这篇文章中的所有答案(django= 1.11.6)。但是,参考@Lorenzo和@Zags的答案,我决定编写一个简单的中间件。

So adding to other good answers,

加上其他的好答案,

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

#1


82  

You can achieve this using the cache_control decorator. Example from the documentation:

您可以使用cache_control decorator实现这一点。文档的例子:

from django.views.decorators.cache import never_cache

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

#2


44  

This approach (slight modification of L. De Leo's solution) with a custom middleware has worked well for me as a site wide solution:

这种方法(稍微修改了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

This makes use of add_never_cache_headers.

这就使用了add_never_cache_header。


If you want to combine this with UpdateCacheMiddleware and FetchFromCacheMiddleware, to enable server-side caching while disabling client-side caching, you need to add DisableClientSideCachingMiddleware before everything else, like this:

如果您想要将它与updatecachemileware和fetchfromcachemileware结合起来,以便在禁用客户端缓存的同时启用服务器端缓存,那么您需要在一切之前添加DisableClientSideCachingMiddleware中间件,如下所示:

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

#3


14  

To supplement existing answers. Here is a decorator that adds additional headers to disable caching:

补充现有的答案。这里有一个decorator,它添加了附加的header来禁用缓存:

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

And you can use it like:

你可以这样使用:

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

#4


7  

Actually writing my own middleware was easy enough:

实际上,编写自己的中间件非常简单:

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

Still doesn't really behave like i wanted but so neither does the @never_cache decorator

仍然不像我想的那样,但是@never_cache decorator也是如此

#5


5  

Regarding the Google Chrome browser (Version 34.0.1847.116 m) and the other browsers, I found that only the @cache_control decorator is working. I use Django 1.6.2.

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

Use it like this:

使用它是这样的:

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

#6


2  

Here is a rewrite of @Meilo's answer for Django 1.10+:

下面重写@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

#7


0  

I was scratching my head when the three magic meta didn't work in Firefox and Safari.

当这三个神奇的元数据在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" />

Apparently it can happen because some browsers will ignore the client side meta, so it should be handled at server side.

显然,这可能发生,因为一些浏览器会忽略客户端元数据,所以应该在服务器端处理它。

I tried all the answers from this post for my class based views (django==1.11.6). But referring to answers from @Lorenzo and @Zags, I decided to write a middleware what I think is a simple one.

我为基于类的视图尝试了这篇文章中的所有答案(django= 1.11.6)。但是,参考@Lorenzo和@Zags的答案,我决定编写一个简单的中间件。

So adding to other good answers,

加上其他的好答案,

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