Django、子域和 mod_rewrite。 URL 搞乱了部署设置

发布于 2024-09-14 03:00:08 字数 1348 浏览 4 评论 0原文

我有一个由 example.com 提供服务的 Django 应用程序。它包含许多子应用程序(例如)强度速度技能。 URL 方案类似于 http://example.com/strengthhttp://example.com/speedhttp://example.com /技能。这就是我运行我的开发服务器的方式(使用 runserver),没有任何问题。

现在,在部署过程中,我需要有映射到这些子应用程序的子域。更具体地说,我希望 http://x.example.com 映射到 http://example.com/x (对于上述 x 值),然后可以继续处理。

我用谷歌搜索了一下,发现有两种方法可以做到这一点。

  • 一种是使用一些中间件来获取 URL 的子域部分,并将其保存在传递给我的视图方法的 request 对象中。然后我在我的应用程序逻辑中完成整个事情。
  • 另一种是使用 Apache mod_rewrite 进行上述 URL 转换,然后让我的应用程序照常运行。

我选择了后者,因为它看起来更整洁,而且我认为我不必在核心应用程序中包含部署特定的代码。

现在,我被一个问题困扰,找不到解决的办法。在 skill 应用程序中,我有一个名为 skill_home 的 URL。它是http://example.com/skill。但是,部署后,skill_home URL 将变为 http://skill.example.com/skill。 Django 将 /skill 附加到顶级域,这就是我得到的。如果我对此 URL 执行 GET,mod_rewrite 会将其更改为 http://skill.example.com/skill/skill,但它不起作用。

我的 mod_rewrite 代码片段如下所示

RewriteCond %{HTTP_HOST} !www.example.com$ [NC]
RewriteCond %{HTTP_HOST} ^(www.)?skill.example.com [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) /skill/$1 

我该如何巧妙地解决这个问题?

I have a Django application being served of (say) example.com. It contains a number of sub-applications (say) strength, speed and skill. The URL scheme is something like http://example.com/strength, http://example.com/speed and http://example.com/skill. This is how I run my dev server (using runserver) and there are no problems whatsoever.

Now, during deployment, I need to have subdomains that map to these sub-applications. More specifically, I want http://x.example.com to map to http://example.com/x (for the above values of x) and then processing can go on.

I googled a little bit and found two ways of doing this.

  • One is to get some middleware to get the subdomain part of the URL and keep it inside the request object passed to my view methods. I then do the whole thing inside my application logic.
  • The other is to use Apache mod_rewrite to do the above URL translation and then let my app run as usual.

I chose the latter since it looked neater and I thought I wouldn't have to include deployment specific code inside my core application.

Now, I'm bitten by a problem which I can't really find a way out of. Inside the skill application, I have a named url skill_home. It's http://example.com/skill. However, once I deploy, the skill_home URL becomes http://skill.example.com/skill. Django appends the /skill to the top level domain and this is what I get. If I do a GET on this URL, mod_rewrite changes it to http://skill.example.com/skill/skill and it doesn't work.

My mod_rewrite snippets look like this

RewriteCond %{HTTP_HOST} !www.example.com$ [NC]
RewriteCond %{HTTP_HOST} ^(www.)?skill.example.com [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) /skill/$1 

How do I fix this neatly?

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

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

发布评论

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

评论(1

比忠 2024-09-21 03:00:08

对于这个答案,我假设您愿意为每个子域执行 mod_rewrite。我认为这不适用于任何子域(即您提到的x)。

这将删除前导的 /skill/ ,以便您的应用程序将继续工作:

RewriteCond %{HTTP_HOST} !www.example.com$ [NC]
RewriteCond %{HTTP_HOST} ^(www.)?skill.example.com [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (/skill/)?(.*) /skill/$2

更新

好的,所以您想删除链接本身中 URL 的前导部分。

基本上,这意味着您必须编写一个自定义标记来替换 {% url %} 标记,如下所示:

import re
from django.template import Library
from django.template.defaulttags import URLNode, url

register = Library()

class SubdomainURLNode(URLNode):
    def render(self, context):
        domain = context['request'].get_host()
        subdomain = re.sub(r'^www\.','',domain).split('.')[0]
        path = super(SubdomainURLNode, self).render(context)
        return re.sub(r'^/%s/' % subdomain, '/', path)

@register.tag
def subdomainurl(parser, token, node_cls=SubdomainURLNode):
    """Just like {% url %} but checks for a subdomain."""
    node_instance = url(parser, token)
    return node_cls(view_name=node_instance.view_name,
        args=node_instance.args,
        kwargs=node_instance.kwargs,
        asvar=node_instance.asvar)

我已经在我的服务器上测试了它,它似乎可以工作。

For this answer I'm assuming that you're willing to do a mod_rewrite for each subdomain. I don't think this will work for any subdomain (i.e. the x you mention).

This will strip out the leading /skill/ so that your app will continue to work:

RewriteCond %{HTTP_HOST} !www.example.com$ [NC]
RewriteCond %{HTTP_HOST} ^(www.)?skill.example.com [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (/skill/)?(.*) /skill/$2

Update

Okay, so you want to strip out the leading part of the URL in the link itself.

Basically, that means you have to write a custom tag to replace the {% url %} tag, something like this:

import re
from django.template import Library
from django.template.defaulttags import URLNode, url

register = Library()

class SubdomainURLNode(URLNode):
    def render(self, context):
        domain = context['request'].get_host()
        subdomain = re.sub(r'^www\.','',domain).split('.')[0]
        path = super(SubdomainURLNode, self).render(context)
        return re.sub(r'^/%s/' % subdomain, '/', path)

@register.tag
def subdomainurl(parser, token, node_cls=SubdomainURLNode):
    """Just like {% url %} but checks for a subdomain."""
    node_instance = url(parser, token)
    return node_cls(view_name=node_instance.view_name,
        args=node_instance.args,
        kwargs=node_instance.kwargs,
        asvar=node_instance.asvar)

I've tested this on my server and it appears to work.

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