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

如何通过django-cors-headers从数据库动态填充CORS_ORIGIN_WHITELIST?

解决Django动态CORS域名白名单的问题

嘿,这个场景我太熟悉了——django-cors-headers的静态白名单确实没法直接从数据库拉取,毕竟settings在应用启动前就加载完了,模型还没初始化呢。不过有几个实用的办法能搞定这个问题:

方案一:自定义动态CORS中间件

中间件是在请求处理阶段运行的,这时候模型已经完全加载,完全可以查询数据库。我们可以写一个自定义中间件,在每次请求时检查Origin是否在你的Website模型里,再决定是否允许跨域。

步骤1:创建自定义中间件

在你的app下新建middleware.py,写入以下代码:

from django.utils.deprecation import MiddlewareMixin
from django.core.cache import cache
from your_app.models import Website  # 替换成实际的app名

class DynamicCORSOriginMiddleware(MiddlewareMixin):
    def process_request(self, request):
        origin = request.META.get('HTTP_ORIGIN')
        if not origin:
            return None
        
        # 先从缓存取允许的域名(后面会说缓存优化)
        allowed_origins = cache.get('allowed_cors_origins', [])
        # 如果缓存没命中,直接查数据库并更新缓存
        if not allowed_origins:
            allowed_origins = list(Website.objects.values_list('domain', flat=True))
            cache.set('allowed_cors_origins', allowed_origins, 3600)  # 缓存1小时
        
        if origin in allowed_origins:
            # 告诉django-cors-headers这个Origin是允许的
            request.META['CORS_ALLOW_ORIGIN'] = origin
        
        return None

步骤2:注册中间件

在settings.py的MIDDLEWARE列表里,把这个自定义中间件放到CorsMiddleware前面:

MIDDLEWARE = [
    # ... 其他中间件(比如SecurityMiddleware等)
    'your_app.middleware.DynamicCORSOriginMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    # ... 其他中间件
]

方案二:自动更新缓存(可选优化)

上面的方案用了缓存减少数据库查询,但如果Website模型的域名有更新,缓存不会自动同步。我们可以用Django信号来解决这个问题:

步骤1:创建信号处理函数

在app下新建signals.py:

from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.core.cache import cache
from your_app.models import Website

@receiver([post_save, post_delete], sender=Website)
def refresh_cors_cache(sender, instance, **kwargs):
    # 当域名添加/修改/删除时,更新缓存
    allowed_origins = list(Website.objects.values_list('domain', flat=True))
    cache.set('allowed_cors_origins', allowed_origins, 3600)

步骤2:注册信号

在app的apps.py里的ready方法中导入信号:

from django.apps import AppConfig

class YourAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'your_app'

    def ready(self):
        import your_app.signals  # 导入信号使其生效

注意事项

  • 确保数据库里的domain字段存储的是完整的Origin(比如https://example.com,而不是只存example.com),否则请求的Origin和数据库值不匹配会导致验证失败。
  • 如果你的业务对域名更新的实时性要求极高,可以缩短缓存过期时间,或者在域名变更时手动触发缓存刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:53:02