Django、子域名与mod_rewrite。部署时URL混乱问题
我有一个Django应用程序,运行在比如说 example.com
上。这个应用里有几个子应用,比如 strength
、speed
和 skill
。它们的访问地址分别是 http://example.com/strength
、http://example.com/speed
和 http://example.com/skill
。在开发的时候,我用 runserver
启动服务器,一切都很顺利。
但是在部署的时候,我需要设置子域名来对应这些子应用。具体来说,我想让 http://x.example.com
对应到 http://example.com/x
(这里的 x
是上面提到的值),然后就可以继续处理请求了。
我查了一下,发现有两种方法可以做到这一点。
- 一种是使用中间件来获取URL中的子域名部分,然后把它保存在传给视图方法的
request
对象里。接着我可以在应用逻辑中处理这些信息。 - 另一种是使用Apache的
mod_rewrite
来进行URL的转换,然后让我的应用正常运行。
我选择了后者,因为看起来更整洁,而且我觉得这样就不需要在核心应用中加入与部署相关的代码。
不过,现在我遇到了一个问题,找不到解决办法。在 skill
应用里,我有一个命名的URL叫 skill_home
,它的地址是 http://example.com/skill
。但是一旦部署后,skill_home
的URL变成了 http://skill.example.com/skill
。Django把 /skill
加到了顶级域名后面,这就是我得到的结果。如果我访问这个URL,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
我该怎么优雅地解决这个问题呢?
1 个回答
在这个回答中,我假设你愿意为每个子域名做一个 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 %} 标签,类似这样:
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)
我在我的服务器上测试过,这个方法似乎有效。