开发环境使用django-hosts时Django子域名如何正确加载媒体文件
故障原因
这个问题本质是django-hosts的子域名路由隔离机制,和开发环境媒体文件服务配置不匹配导致的:
- 你当前配置里
blog子域名独立加载blog.urls下的路由,完全没有继承根URLCONF里的开发环境媒体文件映射规则。访问子域名时,浏览器对相对路径图片/media/xxx.jpg的请求会发到blog.localhost:8000/media/xxx.jpg,但子域名路由表里根本没配媒体文件的处理逻辑,直接返回404。 - 把blog应用挂载到主域名
/blog/路径下时,所有请求都走根URLCONF,能正常匹配到你在根urls.py里加的static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)媒体服务规则,所以图片加载正常。 - 还有个隐性问题:如果
MEDIA_URL用的是相对路径,ckeditor和sorl-thumbnail生成的图片地址会默认跟随当前访问域名,后续跨子域访问还可能碰到跨域拦截、资源权限异常。
修复方案
开发环境修复
- 给所有子域名追加公共媒体路由
不要把媒体文件路由只写在根urls.py里,修改hosts.py,把媒体路由配置为所有子域名都生效的公共规则:from django.conf import settings from django.conf.urls.static import static from django_hosts import patterns, host # 公共路由:所有子域名共用的静态、媒体文件处理规则 public_routes = [ ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) # 如果静态文件在子域名下也加载失败,追加下面这行 # + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) host_patterns = patterns('', host(r'blog', (public_routes, 'blog.urls'), name='blog'), host(r'(|www)', (public_routes, settings.ROOT_URLCONF), name='www'), ) - 统一媒体资源路径规则
建议把settings.py里的MEDIA_URL配置为固定绝对路径,指向主域名的媒体服务地址,避免不同子域名下生成错误的相对资源路径:# 开发环境示例 MEDIA_URL = 'http://localhost:8000/media/' # 如果希望子域名也能直接承载媒体请求,也可以保留相对根路径配置 # MEDIA_URL = '/media/' - 处理跨域问题
如果用了固定主域名的媒体地址,在settings.py里添加跨域配置,避免子域名页面加载主域名图片时被浏览器同源策略拦截:SECURE_CROSS_ORIGIN_OPENER_POLICY = 'same-origin-allow-popups' # 如果你安装了django-cors-headers,记得把主域名、所有子域名都加入允许列表
生产环境注意事项
生产环境下Django本身不处理静态、媒体文件请求,这类资源统一由Nginx等前端Web服务拦截/media/路径直接返回,和Django路由无关,只要保证两点就不会出问题:
- 所有绑定到站点的子域名(blog.xxx.com、www.xxx.com),在Nginx配置里都写了相同的
/media/路径映射,指向服务器上的媒体文件存储目录 - 如果媒体资源放在CDN上,直接把
MEDIA_URL配置为CDN的绝对地址即可,完全和子域名路由解耦。
内容的提问来源于stack exchange,提问作者Ehsan B
相关产品推荐
相关产品推荐

