Django 主机名中间件被缓存

发布于 2024-12-01 07:04:26 字数 1422 浏览 1 评论 0原文

我创建了一个 Django 项目来管理两个共享一些后端代码的独立站点。这两个网站都位于不同的应用程序内。每个应用程序都有自己的 models.py、views.py、模板等...

为了能够对不同的主机名做出不同的反应,我创建了一个 URLconf 中间件:

class HostnameBasedUrlconfMiddleware(object):
    """This middleware parses the hostname from the request, and selects the
    urlconf accordingly.

    To set a custom urlconf according to the current hostname, add an URLCONF
    dictionary to your settings.py file.

    URLCONF = {
        'example.com': 'urls_example',
        'example.dev': 'urls_dev',
        'admin.example.dev': 'apps.admin.urls'
    }

    If the hostname is not found in the URLCONF dictionary, the default
    ROOT_URLCONF setting will be used.

    """

    def process_request(self, request):
        # Decide which urlconf to use. Fallback is to use the ROOT_URLCONF
        # as defined in the settings.py file.
        try:
            hostname = request.META['HTTP_HOST']
            request.urlconf = settings.URLCONF[hostname]
        except (KeyError, AttributeError):
            pass

        return None

一开始这似乎有效,但后来我意识到某种缓存一定正在发生。

当启动服务器并请求站点A时,它就会出现。如果我随后请求站点 B,站点 A 就会出现。有时(但并非总是),经过几次重新加载后,站点 B 最终会出现。重新启动服务器并请求站点 B 后,它会显示出来,但现在站点 A 将显示站点 B 的内容。

内置开发服务器和gunicorn 都发生过这种情况。

我尝试使用curl请求该网站以避免浏览器缓存,没有区别。

我还怀疑这可能是某种模板名称冲突,但所有模板都位于各自模板文件夹内唯一命名的子文件夹内。

我没有安装 memcached,也没有使用任何缓存中间件。

可能是什么问题?是否有一些内部自动缓存正在进行?

I created a Django project to manage two separate sites that share some backend code. Both of the sites are inside separate apps. Each app has its own models.py, views.py, templates etc...

To be able to react differently to different hostnames, I created an URLconf middleware:

class HostnameBasedUrlconfMiddleware(object):
    """This middleware parses the hostname from the request, and selects the
    urlconf accordingly.

    To set a custom urlconf according to the current hostname, add an URLCONF
    dictionary to your settings.py file.

    URLCONF = {
        'example.com': 'urls_example',
        'example.dev': 'urls_dev',
        'admin.example.dev': 'apps.admin.urls'
    }

    If the hostname is not found in the URLCONF dictionary, the default
    ROOT_URLCONF setting will be used.

    """

    def process_request(self, request):
        # Decide which urlconf to use. Fallback is to use the ROOT_URLCONF
        # as defined in the settings.py file.
        try:
            hostname = request.META['HTTP_HOST']
            request.urlconf = settings.URLCONF[hostname]
        except (KeyError, AttributeError):
            pass

        return None

This seemed to work at first, but then I became aware that some kind of caching must be happening.

When starting the server and requesting site A, it would show up. If I then request site B, site A shows up. Sometimes (but not always), after several reloads, site B would finally show up. After restarting the server and requesting site B, it would show up, but now site A would show site B content.

This happened with the builtin devserver as well as with gunicorn.

I tried to request the site with curl to avoid browser caching, no difference.

I also suspected it could be some kind of template name collision, but all templates are inside a uniquely named subfolder inside their respective template folders.

I don't have memcached installed and I'm not using any caching middleware.

What could be the problem? Is there some internal automatic caching going on?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你另情深 2024-12-08 07:04:26

以下是在 urlconf 中替换的代码(至少适用于 1.3):

django.core.handlers.base

class BaseHandler(object):

   [...snip...]

   def get_response(self, request):
        "Returns an HttpResponse object for the given HttpRequest"
        from django.core import exceptions, urlresolvers
        from django.conf import settings

        try:
            # Setup default url resolver for this thread, this code is outside
            # the try/except so we don't get a spurious "unbound local
            # variable" exception in the event an exception is raised before
            # resolver is set
            urlconf = settings.ROOT_URLCONF
            urlresolvers.set_urlconf(urlconf)
            resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
            try:
                response = None
                # Apply request middleware
                for middleware_method in self._request_middleware:
                    response = middleware_method(request)
                    if response:
                        break

                if response is None:
                    if hasattr(request, "urlconf"):
                        # Reset url resolver with a custom urlconf.
                        urlconf = request.urlconf
                        urlresolvers.set_urlconf(urlconf)
                        resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
    [...snip...]

因此,看起来它只是直接使用来自 request 的值。 urlconf。并且您的中间件直接设置 request 值。

我会安装 django-debug-toolbar 来确认是否request.urlconf 的值不是 a) 正在设置或 b) 正在更改。

为了绝对确定,为什么不暂时将代码更改为类似以下内容:

            request.urlconf = settings.URLCONF[hostname]
            request.urlconf_set = datetime.datetime.now()

然后您可以查看调试工具栏中的值(或只是将它们输出到模板中)以查看可能发生的情况。

但是,我建议您不要使用中间件,而只需为每个域设置不同的 settings.py 文件。然后,在您使用的任何 Web 服务器中,将每个服务器设置为使用自己的 .wsgi 文件,该文件指向其自己的设置文件,如下所示:

settings_a.py

from settings import *
ROOT_URLCONF = 'urls_a.py'

settings_b。 py

from settings import *
ROOT_URLCONF = 'urls_b.py'

Here is the code in question that substitutes in the urlconf (for 1.3 at least):

django.core.handlers.base:

class BaseHandler(object):

   [...snip...]

   def get_response(self, request):
        "Returns an HttpResponse object for the given HttpRequest"
        from django.core import exceptions, urlresolvers
        from django.conf import settings

        try:
            # Setup default url resolver for this thread, this code is outside
            # the try/except so we don't get a spurious "unbound local
            # variable" exception in the event an exception is raised before
            # resolver is set
            urlconf = settings.ROOT_URLCONF
            urlresolvers.set_urlconf(urlconf)
            resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
            try:
                response = None
                # Apply request middleware
                for middleware_method in self._request_middleware:
                    response = middleware_method(request)
                    if response:
                        break

                if response is None:
                    if hasattr(request, "urlconf"):
                        # Reset url resolver with a custom urlconf.
                        urlconf = request.urlconf
                        urlresolvers.set_urlconf(urlconf)
                        resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
    [...snip...]

So, it looks like it's just using the value directly from request.urlconf. And your middleware is setting the request value directly.

I'd install django-debug-toolbar to confirm whether or not the value for request.urlconf is a) being set or b) being changed along the way.

To make absolutely sure, why not change the code temporarily to something like:

            request.urlconf = settings.URLCONF[hostname]
            request.urlconf_set = datetime.datetime.now()

Then you can look at the values in the debug toolbar (or just output them in a template) to see what might be going on.

However, I would suggest instead of using middleware, that you simply set up different settings.py files for each domain. Then, in whatever web server you're using, set each one up to use its own .wsgi file, which points to its own settings file, like so:

settings_a.py:

from settings import *
ROOT_URLCONF = 'urls_a.py'

settings_b.py

from settings import *
ROOT_URLCONF = 'urls_b.py'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文