Django кэширует многодоменный поддомен (подстановочный знак), возвращая тот же контент

У меня странная проблема - надеюсь, кто-то уже сталкивался с подобной проблемой.

Я пытаюсь кэшировать содержимое из разных поддоменов, подключенных через подстановочный знак к моему приложению django «example.com».

Итак, когда я доберусь до subdomain1.example.com. я запускаю код, отличный от example.com - простое промежуточное программное обеспечение для этого, например здесь: для субдоменов

Что-то идет не так, когда я одновременно обновляю страницы из разных доменов (например, используя другой браузер вкладок). В результате выводится последняя обновленная страница. И такое поведение не зависит от IP (если кто-то еще переходит на какой-то другой поддомен в то же время, когда вы входите на главную страницу, вы получите контент этого поддомена).

Если я сначала жду загрузки страницы, то я перехожу к другим, все загружается правильно: |

Если я отключу кеширование, проблемы не будет.

Моя мягкая спецификация:

  • Убунту 8.04 ЛТС
  • Apache + mod-wsgi
    • threads 10 processes not defined multiprocess=false
  • Джанго 1.23
  • серверная часть кэширования файлов

ПРОМЕЖУТОЧНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ:

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)   

ПОСМОТРЕТЬ:

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)

НАСТРОЙКИ.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',
)

Чтобы изменить CACHE_KEY, я использую хак: кэширование Django для поддоменов


person lechup    schedule 20.10.2010    source источник
comment
Вам нужно будет показать код представления и то, как вы его кешируете.   -  person Daniel Roseman    schedule 20.10.2010
comment
Я предполагаю, что вы используете один кеш для всех поддоменов. В этом случае добавьте поддомен в качестве префикса к ключу кеша. В противном случае разные субдомены перезапишут кэшированные элементы друг друга.   -  person OmerGertel    schedule 20.10.2010
comment
@OmerGertel: я использовал разные способы изменения CACHE_KEY - закончился stackoverflow.com/questions/772050/ . И я запускал эту проблему в начале :) Теперь, когда я не делаю одновременный запрос, все в порядке - я получаю другой контент. Мне интересно, не настроен ли Apache / mod_wsgi каким-либо образом для вмешательства в кеш django - я должен проверить заголовки.   -  person lechup    schedule 20.10.2010
comment
@ Даниэль, я только что добавил код :)   -  person lechup    schedule 20.10.2010
comment
Да, чуть не забыл - на моем сервере РАЗРАБОТКИ все в порядке :| Я могу нажимать обновление столько раз, сколько захочу, на нескольких вкладках - может быть, это проблема с потоками / процессами? Я предполагаю, что сервер DEV - это один процесс и поток?   -  person lechup    schedule 20.10.2010
comment
Вы используете аналитику Google? codekoala.com/blog/2010/site-wide-caching-django Кроме того, возможно, промежуточное ПО субдоменов должно быть первым, если оно изменяет запрос.   -  person OmerGertel    schedule 20.10.2010
comment
Я попробую! Что касается положения промежуточного программного обеспечения - оно должно быть перед FetchFromCacheMiddleware - потому что оно работает по запросу. UpdateCacheMoiddleware работает с ответом, так что я думаю, это вообще не имеет значения? Или я что-то упускаю? :)   -  person lechup    schedule 24.10.2010


Ответы (2)


После некоторого размышления и прочтения документации о кэшировании я перешел к более простому решению, которое не требует модификации django:

  • добавить субдомен промежуточного программного обеспечения, как указано ниже
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
  • добавьте промежуточное ПО в свои классы промежуточного ПО в settings.py (обратите внимание на django.contrib.messages.middleware.MessageMiddleware и django.contrib.auth.middleware.AuthenticationMiddleware + кэширование на уровне сеанса проблема)
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',
)
  • в представлениях использовать

из django.views.decorators.vary импорт Vari_on_headers

@vary_on_headers('X-поддомен')

person lechup    schedule 14.03.2012

Наконец-то я нашел решение своей проблемы! Проблема заключалась в том, что у меня было установлено две версии django (egg + setup.py). В результате я изменил не ту функцию utils/cache.py _i18n_cache_key_suffix() (я добавляю host в 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

Так что же делать, если вы хотите кэшировать субдомен?

  • если вы используете что-то, изменяющее ваши файлы cookie при каждом запросе (например, Google Analytics), включите промежуточное ПО StripCookies:

    класс StripCookies(объект):
    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
    
  • измените /path/to/django/utils/cache.py и функцию _i18n_cache_key_suffix(), упомянутую в этом сообщении

person lechup    schedule 10.11.2010