我正在尝试将带有Python 3.7应用程序的Django 2.1与React 16.6前端一起提供给AWS Elastic Beanstalk。我使用“创建React应用”来构建React应用。
到目前为止,我已成功使服务器运行(I serve React's index.html
via a TemplateView)并与数据库连接。我现在有点卡住了将S3存储桶连接到我的模板视图。
这里是问题:
python manage.py collectstatic
工作正常(当我访问默认的Django管理页面时,登录名的样式正确),但是当我尝试访问我的React路由之一时,该页面只是空白。使用chrome dev工具,我可以推断出index.html
已正确加载,但是网络请求失败,并显示以下信息:
GET http://<my-eb-url>.elasticbeanstalk.com/static/js/main.a1cf6ce7.chunk.js net::ERR_ABORTED 404 (Not Found)
显然,错误是Django不在存储桶中寻找React,而是在相对文件路径中寻找React。我该如何更改?我的意思是,因为collectstatic
有效,所以Python配置应该不错。
这是React的index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="/favicon.ico" />
<meta
name="viewport"
content="minimum-scale=1,initial-scale=1,width=device-width,shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Roboto+Slab:400,700"
/>
<!-- <link rel="stylesheet" href="/fonts/fonts.css" /> -->
<link rel="manifest" href="/manifest.json" />
<title>Pontem</title>
<link href="/static/css/main.0ebf21be.chunk.css" rel="stylesheet" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script>
!(function(l) {
function e(e) {
for (var r, t, n = e[0], o = e[1], u = e[2], f = 0, i = []; f < n.length; f++)
(t = n[f]), p[t] && i.push(p[t][0]), (p[t] = 0);
for (r in o) Object.prototype.hasOwnProperty.call(o, r) && (l[r] = o[r]);
for (s && s(e); i.length; ) i.shift()();
return c.push.apply(c, u || []), a();
}
function a() {
for (var e, r = 0; r < c.length; r++) {
for (var t = c[r], n = !0, o = 1; o < t.length; o++) {
var u = t[o];
0 !== p[u] && (n = !1);
}
n && (c.splice(r--, 1), (e = f((f.s = t[0]))));
}
return e;
}
var t = {},
p = { 2: 0 },
c = [];
function f(e) {
if (t[e]) return t[e].exports;
var r = (t[e] = { i: e, l: !1, exports: {} });
return l[e].call(r.exports, r, r.exports, f), (r.l = !0), r.exports;
}
(f.m = l),
(f.c = t),
(f.d = function(e, r, t) {
f.o(e, r) || Object.defineProperty(e, r, { enumerable: !0, get: t });
}),
(f.r = function(e) {
"undefined" != typeof Symbol &&
Symbol.toStringTag &&
Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }),
Object.defineProperty(e, "__esModule", { value: !0 });
}),
(f.t = function(r, e) {
if ((1 & e && (r = f(r)), 8 & e)) return r;
if (4 & e && "object" == typeof r && r && r.__esModule) return r;
var t = Object.create(null);
if (
(f.r(t),
Object.defineProperty(t, "default", { enumerable: !0, value: r }),
2 & e && "string" != typeof r)
)
for (var n in r)
f.d(
t,
n,
function(e) {
return r[e];
}.bind(null, n)
);
return t;
}),
(f.n = function(e) {
var r =
e && e.__esModule
? function() {
return e.default;
}
: function() {
return e;
};
return f.d(r, "a", r), r;
}),
(f.o = function(e, r) {
return Object.prototype.hasOwnProperty.call(e, r);
}),
(f.p = "/");
var r = (window.webpackJsonp = window.webpackJsonp || []),
n = r.push.bind(r);
(r.push = e), (r = r.slice());
for (var o = 0; o < r.length; o++) e(r[o]);
var s = n;
a();
})([]);</script
><script src="/static/js/1.f9c0bd2f.chunk.js"></script
><script src="/static/js/main.a1cf6ce7.chunk.js"></script>
</body>
</html>
附录 我觉得错误不是由Python引起的。但是只是因为它可能会有所帮助,所以这是我的python设置。还有我的点子包。
base.py
:
"""
Django settings for hrdinner project.
"""
import os
import sys
from pathlib import Path
from django.core.exceptions import ImproperlyConfigured
def get_env_variable(var_name):
"""Get the environment variable or return exception."""
try:
return os.environ[var_name]
except KeyError:
error_msg = 'Set the {} environment variable'.format(var_name)
raise ImproperlyConfigured(error_msg)
# Build paths inside the project like this: BASE_DIR / 'media'
BASE_DIR = Path(__file__).resolve().parent.parent
# Tell Django where to look for the apps.
sys.path.append(str(BASE_DIR.parent / 'src'))
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = get_env_variable('DJANGO_SECRET_KEY')
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'model_utils',
'authtools',
'rest_framework',
'rest_framework.authtoken',
# my apps ...
]
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR.parent / 'build'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'config.wsgi.application'
ATOMIC_REQUESTS = True
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
# Password validation
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
AUTHENTICATION_BACKENDS = (
# Needed to login by username in Django admin, regardless of `allauth`
'django.contrib.auth.backends.ModelBackend',
)
LOGIN_URL = "/"
DEBUG_PROPAGATE_EXCEPTIONS = False
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
STATICFILES_DIRS = [BASE_DIR.parent / 'build' / 'static']
# Security
X_FRAME_OPTIONS = 'DENY'
# django-authtools configuration
AUTH_USER_MODEL = 'accounts.User'
# django-rest-framework configuration
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
production.py:
from .aws.conf import *
from .base import *
DEBUG = False
INSTALLED_APPS += [
'storages',
]
ALLOWED_HOSTS += [
# my urls
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': get_env_variable('RDS_DB_NAME'),
'USER': get_env_variable('RDS_USERNAME'),
'PASSWORD': get_env_variable('RDS_PASSWORD'),
'HOST': get_env_variable('RDS_HOSTNAME'),
'PORT': get_env_variable('RDS_PORT'),
}
}
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
SECURE_SSL_HOST = True
# TODO: CHANGE THIS TO A YEAR ONCE YOUR ARE READY! 5 minutes for testing.
SECURE_HSTS_SECONDS = 300
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_CONTENT_TYPE_NOSNIFF = True
conf.py
:
import os
from django.core.exceptions import ImproperlyConfigured
def get_env_variable(var_name):
"""Get the environment variable or return exception."""
try:
return os.environ[var_name]
except KeyError:
error_msg = 'Set the {} environment variable'.format(var_name)
raise ImproperlyConfigured(error_msg)
AWS_ACCESS_KEY_ID = get_env_variable("ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = get_env_variable("SECRET_ACCESS_KEY")
AWS_S3_SIGNATURE_VERSION = 's3v4'
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
AWS_STORAGE_BUCKET_NAME = get_env_variable("AWS_BUCKET_NAME")
AWS_S3_CUSTOM_DOMAIN = '%s.s3.eu-central-1.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_LOCATION = 'static'
STATIC_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
STATICFILES_STORAGE = 'config.settings.aws.utils.StaticRootS3BotoStorage'
DEFAULT_FILE_STORAGE = 'config.settings.aws.utils.MediaRootS3BotoStorage'
MEDIA_URL = 'https://%s.s3.amazonaws.com/media/' % AWS_STORAGE_BUCKET_NAME
MEDIA_ROOT = MEDIA_URL
ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'
utils.py
:
from storages.backends.s3boto3 import S3Boto3Storage
def StaticRootS3BotoStorage(): return S3Boto3Storage(location='static')
def MediaRootS3BotoStorage(): return S3Boto3Storage(location='media')
requirements.txt:
awsebcli==3.14.6
blessed==1.15.0
boto==2.49.0
boto3==1.9.42
botocore==1.12.42
cached-property==1.5.1
cement==2.8.2
certifi==2018.10.15
chardet==3.0.4
colorama==0.3.9
Django==2.1.2
django-annoying==0.10.4
django-authtools==1.6.0
django-model-utils==3.1.2
django-storages==1.7.1
djangorestframework==3.9.0
docker==3.5.1
docker-compose==1.21.2
docker-pycreds==0.3.0
dockerpty==0.4.1
docopt==0.6.2
docutils==0.14
idna==2.6
isort==4.3.4
jmespath==0.9.3
jsonschema==2.6.0
pathspec==0.5.5
psycopg2==2.7.5
python-dateutil==2.7.5
pytz==2018.6
PyYAML==3.13
requests==2.18.4
s3transfer==0.1.13
semantic-version==2.5.0
termcolor==1.1.0
texttable==0.9.1
urllib3==1.22
wcwidth==0.1.7
websocket-client==0.54.0
答案 0 :(得分:1)
您的浏览器正在尝试从相对路径中获取样式表和javascript文件,因为您在index.html
中指定了一个:
<script src="/static/js/1.f9c0bd2f.chunk.js"></script>
由于您使用的是Django来收集静态文件,因此您也可以在模板中使用其template tag to reference static files:
<script src="{% static 'js/1.f9c0bd2f.chunk.js' %}"></script>