加载 Django runserver 提供的静态文件时如何修复 cors 错误

Posted

技术标签:

【中文标题】加载 Django runserver 提供的静态文件时如何修复 cors 错误【英文标题】:How to fix cors error when loading static file served by Django runserver 【发布时间】:2020-10-21 04:55:58 【问题描述】:

相关信息:Django 2.2 版

我已安装 django-cors-headers 并将其添加到启用的应用程序中,并将中间件作为第一个中间件添加到中间件设置中。

我也配置了设置:


INSTALLED_APPS = [
    ...
    "corsheaders",
    "rest_framework",
    "django.contrib.admin",
    ...
]


MIDDLEWARE = [
    ...
    "corsheaders.middleware.CorsMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    ...
]

CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True

我的设置有 2 个项目在不同的端口上运行。 Django 服务器运行在 8000 上,我的前端运行在 8080 上。

前端针对后端发送的所有 API 请求都可以正常工作。但是,当我尝试加载后端项目提供的 one.js 文件时,它会失败并出现以下错误:


Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://127.0.0.1:8000/static/myscript.js. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)

我加载脚本的方式是创建一个新的脚本元素并将 URL http://127.0.0.1:8000/static/myscript.js 添加为脚本标签上 src 属性的值。

当我使用 https://code.jquery.com/jquery-3.5.1.min.js 而不是 http://127.0.0.1:8000/static/myscript.js 之类的值时,不会发生此错误,因此看起来 Django 运行服务器提供的静态文件存在一些问题,但究竟是什么以及为什么超出了我的范围。

我知道有很多与 cors 相关的问题,例如 Django CORS on static asset,但它们与我的问题无关或没有得到答复。另外,我注意到,静态文件的请求无论如何都会绕过 cors 中间件,所以也许我应该在这里做其他事情?

也许有人可以在这里帮助我?

谢谢

【问题讨论】:

【参考方案1】:

看来我已经找到了答案:

我所做的是将INSTALLED_APPS.remove('django.contrib.staticfiles') 添加到开发设置中。

我创建了类似的视图

from django.contrib.staticfiles.views import serve


def cors_serve(request, path, insecure=False, **kwargs):
    kwargs.pop('document_root')
    response = serve(request, path, insecure=insecure, **kwargs)
    response['Access-Control-Allow-Origin'] = '*'
    return response

用于提供静态内容。我像这样将它添加到 urlconf 中:

from utils.views import cors_serve

...

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT, view=cors_serve)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT, view=cors_serve)

这确实为我解决了这个问题。我知道 Django 文档 (https://docs.djangoproject.com/en/2.2/ref/contrib/staticfiles/#runserver) 建议您可以跳过使用 runserver 提供的静态文件,如下所示:django-admin runserver --nostatic 但如果我的 INSTALLED_APPS 中仍然有 "django.contrib.staticfiles",那对我绝对没有影响

【讨论】:

【参考方案2】:

基于 Odif Yitsaeb 的想法略有不同的方法,但是您不需要删除 staticfiles 或混淆 urlpatterns。只需将以下代码放入您的settings.py

from django.contrib.staticfiles import handlers

# extend StaticFilesHandler to add "Access-Control-Allow-Origin" to every response
class CORSStaticFilesHandler(handlers.StaticFilesHandler):
    def serve(self, request):
        response = super().serve(request)
        response['Access-Control-Allow-Origin'] = '*'
        return response

# monkeypatch handlers to use our class instead of the original StaticFilesHandler
handlers.StaticFilesHandler = CORSStaticFilesHandler

注意事项:

不要在生产中使用它(无论如何你都不应该在生产中使用 devserver) 在处理任何请求之前,必须很早就对处理程序进行猴子补丁。将代码放在settings.py 中即可解决问题

【讨论】:

以上是关于加载 Django runserver 提供的静态文件时如何修复 cors 错误的主要内容,如果未能解决你的问题,请参考以下文章

python manage.py runserver 127.0.0.1:8000 启动后台有两个启动进程

Django提供静态文件服务

django 1.6 使用别名和 apache 提供静态管理文件

如何在 Django 1.4 中为本地开发提供静态文件

Django本身提供了runserver,为啥不用来部署

部署 --- Nginx