You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Django+React的多租户应用子域名路由配置问询

多租户子域名方案:Django+React全栈配置指南

一、DNS与Nginx服务器配置

DNS设置

在域名服务商后台添加通配符DNS记录,让所有子域名指向你的服务器IP:

  • 记录类型选A(或CNAME,若用负载均衡)
  • 主机记录填*
  • 记录值填服务器公网IP

这样所有形如username.mywebsite.com的子域名都会解析到你的服务器。

Nginx配置

配置Nginx监听所有子域名请求,转发给Django的WSGI服务(如Gunicorn)。示例配置:

server {
    listen 80;
    server_name *.mywebsite.com;

    # 静态文件直接由Nginx处理(比Django托管更高效,可选)
    location /static/ {
        root /path/to/your/django/project;
        expires 30d;
    }

    # React build静态资源路由
    location /static/react/ {
        root /path/to/your/react/build;
        expires 30d;
    }

    # 所有动态请求转发给Django
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

若需保持Django托管React build的原有逻辑,可跳过Nginx的React静态资源配置。

二、Django端修改

1. 子域名提取中间件

编写中间件从请求Host中提取租户标识(用户名),挂载到request对象:

# myproject/middleware.py
class TenantMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # 排除无需解析为租户的特殊子域名
        self.excluded_subdomains = {'www', 'api', 'admin'}

    def __call__(self, request):
        # 去除端口号,提取纯域名部分
        host = request.get_host().split(':')[0]
        domain_parts = host.split('.')
        
        # 兼容二级/三级域名(如mywebsite.com或mywebsite.co.uk)
        if len(domain_parts) >= 2:
            subdomain = domain_parts[0]
            request.tenant_username = subdomain if subdomain not in self.excluded_subdomains else None
        else:
            request.tenant_username = None
        
        response = self.get_response(request)
        return response

在settings.py中注册中间件:

MIDDLEWARE = [
    ...
    'myproject.middleware.TenantMiddleware',
    ...
]

2. 子域名路由处理

推荐用django-hosts库实现子域名到不同URL配置的映射:

  • 安装:pip install django-hosts
  • 在settings.py添加配置:
INSTALLED_APPS = [
    ...
    'django_hosts',
]

MIDDLEWARE = [
    'django_hosts.middleware.HostsRequestMiddleware',  # 放在最前
    ...
    'django_hosts.middleware.HostsResponseMiddleware',  # 放在最后
]

ROOT_HOSTCONF = 'myproject.hosts'
DEFAULT_HOST = 'www'  # 主域名默认路由
  • 创建myproject/hosts.py:
from django_hosts import patterns, host

host_patterns = patterns('',
    # 主域名(www.mywebsite.com)使用默认urls.py
    host(r'www', 'myproject.urls', name='www'),
    # 租户子域名(username.mywebsite.com)使用专属路由配置
    host(r'(?P<username>[a-zA-Z0-9_-]+)', 'myproject.tenant_urls', name='tenant'),
)
  • 创建myproject/tenant_urls.py,配置租户专属路由:
from django.urls import path, re_path
from django.views.generic import TemplateView
from django.views.static import serve
import os

react_build_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'react', 'build')

urlpatterns = [
    # 托管React build静态文件
    re_path(r'^static/(?P<path>.*)$', serve, {'document_root': os.path.join(react_build_dir, 'static')}),
    # Catch-all路由,返回React index.html处理前端路由
    re_path(r'^.*$', TemplateView.as_view(template_name='index.html')),
    # 租户专属API路由
    path('api/tenant/', include('tenant_api.urls')),
]

3. 多租户数据过滤

在DRF视图中通过request.tenant_username过滤数据:

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import TenantData
from .serializers import TenantDataSerializer

class TenantDataView(APIView):
    def get(self, request):
        if not request.tenant_username:
            return Response({'error': '无效租户'}, status=400)
        
        # 根据用户名过滤租户数据
        data = TenantData.objects.filter(user__username=request.tenant_username)
        serializer = TenantDataSerializer(data, many=True)
        return Response(serializer.data)

三、React端调整

1. 前端路由适配

  • 保持React路由为相对路径(如/dashboard),不要硬编码主域名
  • 依赖Django租户路由中的catch-all规则,确保子域名下所有路径都返回React的index.html

2. API请求适配

将API请求改为相对路径,避免硬编码主域名:

// 错误写法:硬编码主域名
axios.get('https://mywebsite.com/api/tenant/data')

// 正确写法:相对路径
axios.get('/api/tenant/data')

这样无论当前是主域名还是子域名,请求都会自动适配当前域名。

3. 环境变量配置

本地测试时在.env中设置API前缀为相对路径:

REACT_APP_API_URL=/api

生产环境保持相同配置即可。

四、本地测试子域名配置

1. 修改本地hosts文件

在/etc/hosts(Linux/macOS)或C:\Windows\System32\drivers\etc\hosts(Windows)中添加:

127.0.0.1 alice.localhost
127.0.0.1 bob.localhost

让alice.localhost和bob.localhost指向本地服务器。

2. Django配置调整

在settings.py中允许本地子域名:

ALLOWED_HOSTS = ['*.localhost', '127.0.0.1']

3. 启动服务测试

  • 启动Django服务:python manage.py runserver
  • 访问http://alice.localhost:8000,检查中间件是否正确提取alice作为租户用户名
  • 测试React路由和API请求是否正常工作

五、异常处理建议

  • 当子域名对应的用户名不存在时,可在中间件或视图中返回404页面,或重定向到主域名注册页
  • 对api.mywebsite.com这类特殊子域名单独配置路由,避免误解析为租户

内容的提问来源于stack exchange,提问作者Ajith Chitturi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 02:22:05