woo*_*oof 4 javascript python django reactjs digital-ocean
我正在尝试将我的 React/django Web 应用程序部署到 linux-VM Droplet。我没有使用 webpack 来处理 JS 内容。相反,我npm run build通过 CDN 子域、数字海洋 s3 存储桶提供静态文件。
我能够将python manage.py collectstatic我的 React 生产构建文件夹推送到 CDN。
当我访问我的生产网站时,它当前仅加载一个空白页面,其中包含以下控制台错误:
\nRefused to apply style from \'https://www.my_website_URL.com/static/css/main.ce8d6426.chunk.css\' because its MIME type (\'text/html\') is not a supported stylesheet MIME type, and strict MIME checking is enabled.\n\nRefused to execute script from \'https://www.my_website_URL.com/static/js/2.ca12ac54.chunk.js\' because its MIME type (\'text/html\') is not executable, and strict MIME type checking is enabled.\n\nRefused to execute script from \'https://www.my_website_URL.com/static/js/main.220624ac.chunk.js\' because its MIME type (\'text/html\') is not executable, and strict MIME type checking is enabled.\nRun Code Online (Sandbox Code Playgroud)\n没有任何网络错误为此事提供任何有用的信息。
\n问题必须是服务器端(django)......我认为。
\n项目设立:
\n\nReact 生产版本位于我的核心 django 文件夹内。
\n以下是我如何通过 django 链接 React:
\ncore urls.py
def render_react(request):\n return render(request, "index.html") \n #index.html being created by react, not django templates \n \nurlpatterns = [\n re_path(r"^$", render_react),\n re_path(r"^(?:.*)/?$", render_react),\n ...\n]\nRun Code Online (Sandbox Code Playgroud)\n索引.html
\nRefused to apply style from \'https://www.my_website_URL.com/static/css/main.ce8d6426.chunk.css\' because its MIME type (\'text/html\') is not a supported stylesheet MIME type, and strict MIME checking is enabled.\n\nRefused to execute script from \'https://www.my_website_URL.com/static/js/2.ca12ac54.chunk.js\' because its MIME type (\'text/html\') is not executable, and strict MIME type checking is enabled.\n\nRefused to execute script from \'https://www.my_website_URL.com/static/js/main.220624ac.chunk.js\' because its MIME type (\'text/html\') is not executable, and strict MIME type checking is enabled.\nRun Code Online (Sandbox Code Playgroud)\n设置.py
\nimport os\n\n\nfrom pathlib import Path\nfrom decouple import config\nimport dj_database_url\n\nfrom datetime import timedelta\n\n# Build paths inside the project like this: BASE_DIR / \'subdir\'.\n# BASE_DIR = Path(__file__).resolve().parent.parent\nBASE_DIR = os.path.dirname(os.path.abspath(__file__))\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = config(\'DJANGO_SECRET_KEY\')\n\n# SECURITY WARNING: don\'t run with debug turned on in production!\nDEBUG = True\n\nALLOWED_HOSTS = [\'URL\'s\']\n\nSECURE_PROXY_SSL_HEADER = (\'HTTP_X_FORWARDED_PROTO\', \'https\')\nSESSION_COOKIE_SECURE = True\nCSRF_COOKIE_SECURE = True\nSECURE_SSL_REDIRECT = True\nSESSION_COOKIE_HTTPONLY = True\n\n\nINSTALLED_APPS = [\n \'rest_framework\',\n \'django.contrib.admin\',\n \'django.contrib.auth\',\n \'django.contrib.contenttypes\',\n \'django.contrib.sessions\',\n \'django.contrib.messages\',\n \'django.contrib.staticfiles\',\n\n\n # Third Party Apps #\n \'django_filters\',\n \'corsheaders\',\n \'django_extensions\',\n \'drf_yasg\',\n \'storages\',\n\n\n # Apps\n \'users\',\n \'bucket\',\n \'bucket_api\',\n \n #oauth\n \'oauth2_provider\',\n \'social_django\',\n \'drf_social_oauth2\',\n]\n\nMIDDLEWARE = [\n \'django.middleware.security.SecurityMiddleware\',\n \'django.contrib.sessions.middleware.SessionMiddleware\',\n \'corsheaders.middleware.CorsMiddleware\',\n \'django.middleware.common.CommonMiddleware\',\n \'django.middleware.csrf.CsrfViewMiddleware\',\n \'oauth2_provider.middleware.OAuth2TokenMiddleware\',\n \'django.contrib.auth.middleware.AuthenticationMiddleware\',\n \'django.contrib.messages.middleware.MessageMiddleware\',\n \'django.middleware.clickjacking.XFrameOptionsMiddleware\',\n]\n\nROOT_URLCONF = \'core.urls\'\n\n\nTEMPLATES = [\n {\n \'BACKEND\': \'django.template.backends.django.DjangoTemplates\',\n \'DIRS\' : [os.path.join(BASE_DIR, \'build\')],\n \'APP_DIRS\': True,\n \'OPTIONS\': {\n \'context_processors\': [\n \'django.template.context_processors.debug\',\n \'django.template.context_processors.request\',\n \'django.contrib.auth.context_processors.auth\',\n \'django.contrib.messages.context_processors.messages\',\n \'social_django.context_processors.backends\',\n \'social_django.context_processors.login_redirect\',\n ],\n },\n },\n]\n\nWSGI_APPLICATION = \'core.wsgi.application\'\n\nDATABASES = {\n \'default\': {\n \'ENGINE\': \'django.db.backends.postgresql_psycopg2\',\n \'NAME\': config(\'DJANGO_DB_NAME\'),\n \'USER\' : config(\'DJANGO_DB_ADMIN\'),\n \'PASSWORD\' : config(\'DJANGO_ADMIN_PASS\'),\n \'HOST\' : config(\'DJANGO_DB_HOST\'),\n \'PORT\' : config(\'DJANGO_DB_PORT\'),\n \'OPTIONS\': {\'sslmode\':\'disable\'},\n }\n}\n\n\ndb_from_env = dj_database_url.config(conn_max_age=600)\nDATABASES[\'default\'].update(db_from_env)\n\n\nAUTH_PASSWORD_VALIDATORS = [\n {\n \'NAME\': \'django.contrib.auth.password_validation.UserAttributeSimilarityValidator\',\n },\n {\n \'NAME\': \'django.contrib.auth.password_validation.MinimumLengthValidator\',\n },\n {\n \'NAME\': \'django.contrib.auth.password_validation.CommonPasswordValidator\',\n },\n {\n \'NAME\': \'django.contrib.auth.password_validation.NumericPasswordValidator\',\n },\n]\n\n\n# Internationalization\n# https://docs.djangoproject.com/en/3.1/topics/i18n/\n\nLANGUAGE_CODE = \'en-us\'\n\nTIME_ZONE = \'America/New_York\'\n\nUSE_I18N = True\n\nUSE_L10N = True\n\nUSE_TZ = True\n\n\n# Static files (CSS, JavaScript, Images)\n# https://docs.djangoproject.com/en/3.1/howto/static-files/\n\nAWS_ACCESS_KEY_ID = config(\'AWS_ACCESS_KEY_ID\')\nAWS_SECRET_ACCESS_KEY = config(\'AWS_SECRET_ACCESS_KEY\')\nAWS_STORAGE_BUCKET_NAME = config(\'AWS_STORAGE_BUCKET_NAME\')\nAWS_S3_ENDPOINT_URL = config(\'AWS_S3_ENDPOINT_URL\')\nAWS_S3_CUSTOM_DOMAIN = config(\'AWS_S3_CUSTOM_DOMAIN\')\nAWS_S3_OBJECT_PARAMETERS = {\n \'CacheControl\': \'max-age=86400\',\n}\nAWS_LOCATION = config(\'AWS_LOCATION\')\nAWS_DEFAULT_ACL = \'public-read\'\n\n\nSTATIC_URL = \'{}/{}/\'.format(AWS_S3_ENDPOINT_URL, AWS_LOCATION)\nSTATICFILES_STORAGE = \'storages.backends.s3boto3.S3Boto3Storage\'\nDEFAULT_FILE_STORAGE = \'storages.backends.s3boto3.S3Boto3Storage\'\n\n\nSTATIC_URL = \'/static/\'\nSTATICFILES_DIRS = [\n os.path.join(BASE_DIR, \'static/templates\'),\n os.path.join(BASE_DIR, \'build/static\')\n]\n\nSTATIC_ROOT = os.path.join(BASE_DIR, \'static\')\nRun Code Online (Sandbox Code Playgroud)\n如何修复 Django 以正确地从 CDN 提供生产静态块 css 和 js 文件?如果 Chrome 控制台能够找到错误中的文件,则 CDN 的路径和位置必须正确。
\n如果您需要我提供更多信息,请告诉我。目前陷入困境,没有一个简单的解决方案来修复我的 MIME 类型错误并解决我的网站仅加载空白页面的问题。
\n感谢您的任何帮助/提示/或指导!
\n如果有人想知道,我正在使用 Gunicorn 和 Nginx。
\n编辑:\n添加了赏金以引起人们对这个问题的注意。我没有使用 Django webpack 加载器和 babel。我宁愿不依赖其他可能轻易破坏事情的库。
\n编辑#2:\n我已经添加了 NGINX 配置文件,我应该将流量重定向到此处的 CDN 路径吗?
\nserver {\n listen 80 default_server;\n listen [::]:80 default_server;\n server_name _;\n return 301 https://my_website_URL.io$request_uri;\n}\nserver {\n listen [::]:443 ssl ipv6only=on;\n listen 443 ssl;\n server_name my_website_URL.com www.my_website_URL.com;\n\n # Let\'s Encrypt parameters\n ssl_certificate /etc/letsencrypt/live/my_website_URL.com/fullchain.pem; # managed by Certbot\n ssl_certificate_key /etc/letsencrypt/live/my_website_URL.com/privkey.pem; # managed by Certbot\n include /etc/letsencrypt/options-ssl-nginx.conf;\n ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;\n\n location = /favicon.ico { access_log off; log_not_found off; }\n\n\n\n\n location / {\n proxy_pass http://unix:/run/gunicorn.sock;\n proxy_redirect off;\n\n proxy_set_header Host $http_host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto https;\n }\nRun Code Online (Sandbox Code Playgroud)\n编辑编辑编辑:\n我添加了我的gunicorn 文件,因为我收到了 502 错误网关,并且我的gunicorn 服务给了我这个错误:
\n\xe2\x97\x8f gunicorn.socket - gunicorn socket\n Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; vendor preset: enabled)\n Active: failed (Result: service-start-limit-hit) since Wed 2021-04-28 23:44:16 UTC; 1min 2s ago\n Triggers: \xe2\x97\x8f gunicorn.service\n Listen: /run/gunicorn.sock (Stream)\nRun Code Online (Sandbox Code Playgroud)\n这是我的gunicorn配置:
\n[Unit]\nDescription=gunicorn daemon\nRequires=gunicorn.socket\nAfter=network.target\n\n[Service]\nUser=alpha\nGroup=www-data\nWorkingDirectory=/home/user/srv/project/backend\nExecStart=/home/user/srv/project/backend/venv/bin/gunicorn \\\n --access-logfile - \\\n --workers 3 \\\n --timeout 300 \\\n --bind unix:/run/gunicorn.sock \\\n core.wsgi:application\n\n[Install]\nWantedBy=multi-user.target\n\nRun Code Online (Sandbox Code Playgroud)\n
静态文件 URL 是由 React 而不是 Django 生成的。因此,即使STATIC_URL设置正确,静态文件的 URL 也不会在 Django 中进行模板化,例如使用{% static '' %}.
根据您的设置,Django 正在提供fromTEMPLATES的构建版本(而不是问题中的)。CSS 和 JavaScript 文件(也由 React 构建)的 URL是由 React 而不是 Django 生成的。index.htmlnpm run buildindex.html/staticindex.html
要让 React 生成具有正确前缀的 URL,您可以PUBLIC_URL在运行之前设置环境变量npm run build。目前它将使用默认设置(即/主机的根目录)。
如果您在主机上提供静态文件或使用{% static '' %}. 以供参考:
您的网址之一太贪婪了:
re_path(r"^(?:.*)/?$", render_react),
Run Code Online (Sandbox Code Playgroud)
这将匹配:
static/css/main.ce8d6426.chunk.css
Run Code Online (Sandbox Code Playgroud)
这样该 URL 将解析为您的render_react视图并尝试为您的文件提供服务index.html,因此它认为 MIME 类型是text/html:
Refused to apply style from 'https://www.my_website_URL.com/static/css/main.ce8d6426.chunk.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
Run Code Online (Sandbox Code Playgroud)
如果您想匹配除以 开头的 URI 之外的所有 URI,static您可以在正则表达式中使用否定前瞻:
re_path(r"^(?!static)(?:.*)/?$", render_react),
Run Code Online (Sandbox Code Playgroud)
在 settings.py 中,您将覆盖STATIC_URL将 Django 定向到静态文件的 CDN 的设置:
STATIC_URL = '{}/{}/'.format(AWS_S3_ENDPOINT_URL, AWS_LOCATION)
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATIC_URL = '/static/' # <------- REMOVE
Run Code Online (Sandbox Code Playgroud)
此外,STATIC_URL需要在前面加上https://并使用AWS_S3_CUSTOM_DOMAIN(不是AWS_S3_ENDPOINT_URL):
STATIC_URL = f'https://{AWS_S3_ENDPOINT_URL}/{AWS_LOCATION}/'
Run Code Online (Sandbox Code Playgroud)
您的 NGINX 和 Gunicorn 配置良好。您的 Django 应用程序可能无法正确启动,例如,由于配置错误:
检查日志:
journalctl -u gunicorn.service
Run Code Online (Sandbox Code Playgroud)
运行简单的冒烟测试也很有用(它会打开吗?):
./manage.py runserver
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2065 次 |
| 最近记录: |