开发者

django caching multi domain subdomain (wildcard) returning same content

I've got strange issue - I hope someone run similar problem before.

I'm trying to cache content from different subdomains connected via wildcard to my django application 'example.com'.

So when I get to subdomain1.example.com. i run differend code in view than excample.com - simple middleware for that like here: Django caching for subdomains

The thing is going wrong when I refresh simultonously pages form different domains (eg. using different tab browser). The result produce output of last refreshed page. And such behaviour do not depend on IP (if someone else is going onto some o开发者_Python百科ther subdomain in the same time you are entering main page you will get that subdomain content).

If I wait for loading page first then i move to other everythins is loaded correctly :|

If I turn off caching the problem does not exists.

My soft spec:

  • Ubuntu 8.04 LTS
  • Apache + mod-wsgi
    • threads 10 processes not defined multiprocess=false
  • Django 1.23
  • file caching backend

MIDDLEWARE:

class Subdomains:
    def process_request(self, request):
        u'''
            przekierowuje na stronę główną, jeżeli subdomena z której weszliśmy nie jest subdomeną miasta znajdującego się w bazie. Oraz ustawia zmienną request.META['city']!
        '''
        city = get_city_from_host(request.get_host())
        request.city=None
        if city:
            try:
                city = City.objects.filter(slug__exact=city)
                request.city=city[0].slug
            except:
                return HttpResponsePermanentRedirect(ROOT_URL)   

VIEW:

def post_data(request,address,id):
    url_root = settings.ROOT_URL
    city_subdomain = request.city
    if city_subdomain:
        random_posts = Post.objects.filter(city__slug=city_subdomain).order_by('?')
        if random_posts.count() <= 10:
            pass
        else:
            random_posts = random_posts[:10]

        city = City.objects.filter(slug__exact =  city_subdomain)[0]
        try:
            post = Post.objects.get(id = int(id), city__slug__exact=city.slug)
            nearestinposts = post.nearestinpost_set.select_related(depth=2).all()
            return render_to_response('post_data.html', locals())
        except:
            return HttpResponsePermanentRedirect('http://%s.%s/' % (city_subdomain, settings.ROOT_URL))

    return HttpResponsePermanentRedirect('http://%s' % settings.ROOT_URL)

SETTINGS.PY

CACHE_BACKEND = 'file://%s/cache/' % PROJECT_DIR
CACHE_MIDDLEWARE_SECONDS = 6000
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    'middleware.default.Subdomains',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
)

To modify CACHE_KEY i use hack: Django caching for subdomains


After some consideration and reading some documentation about caching I moved to simpler solution which doesn't require modifing django:

  • add middleware Subdomain as provided below
class Subdomains:
    def process_request(self, request):
        request.META['HTTP_X_SUBDOMAIN'] = request.get_host()


    def process_response(self, request, response):
        response['X-Subdomain'] = request.META['HTTP_X_SUBDOMAIN']
        return response
  • add middleware to Your middleware classes in settings.py (watch out for django.contrib.messages.middleware.MessageMiddleware and django.contrib.auth.middleware.AuthenticationMiddleware + session wide caching issue)
MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.gzip.GZipMiddleware',
    'middleware.default.Subdomains',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware', # we need that to make auth middleware not to add Vary: Cookie to each response
    'django.middleware.cache.FetchFromCacheMiddleware',
)
  • in views use

from django.views.decorators.vary import vary_on_headers

@vary_on_headers('X-Subdomain')


I finally found solution to my problem! The issue was that I had two version of django installed (egg + setup.py). As a result I changed not right utils/cache.py _i18n_cache_key_suffix() function (i'm adding host to cache_key).

def _i18n_cache_key_suffix(request, cache_key):
    """If enabled, returns the cache key ending with a locale."""
    if settings.USE_I18N:
        # first check if LocaleMiddleware or another middleware added
        # LANGUAGE_CODE to request, then fall back to the active language
        # which in turn can also fall back to settings.LANGUAGE_CODE
        cache_key += '.%s' % getattr(request, 'LANGUAGE_CODE', get_language())
    cache_key += '.%s' % (request.get_host())
    return cache_key

So what should You do if you want subdomain caching?

  • if you are using something changing Your cookies on each request (eg. Google Analytics), enable StripCookies middleware:

    class StripCookies(object):
    STRIP_RE = re.compile(r'\b(_[^=]+=.+?(?:; |$))')

    def process_request(self, request):
        cookie = self.STRIP_RE.sub('', request.META.get('HTTP_COOKIE', ''))
        request.META['HTTP_COOKIE'] = cookie
    
  • modify /path/to/django/utils/cache.py and there _i18n_cache_key_suffix() function mentioned in this post

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜