django - Django 和 AWS S3:对错误 URL 的静态文件请求
问题描述
我正在尝试使用带有 React 16.6 前端的 Python 3.7 应用程序为 AWS Elastic Beanstalk 提供 Django 2.1。我使用 Create React App 构建 React 应用程序。
到目前为止,我成功地让服务器运行(我通过 TemplateView为 React 提供服务index.html
)并与数据库连接。我现在有点卡住将 S3 存储桶连接到我的模板视图。
这是问题:
python manage.py collectstatic
工作正常(当我访问默认的 Django 管理页面时,登录的样式正确),但是当我尝试访问我的 React 路由之一时,页面只是空白。使用 chrome 开发工具,我能够推断出index.html
已正确加载,但网络请求失败:
GET http://<my-eb-url>.elasticbeanstalk.com/static/js/main.a1cf6ce7.chunk.js net::ERR_ABORTED 404 (Not Found)
所以显然错误是 Django 不在存储桶中查找 React,而是在相对文件路径中查找。我怎样才能改变这个?我的意思是 Python 配置应该很好,因为collectstatic
工作。
这是 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 设置。还有我的 pip 包。
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
解决方案
您的浏览器正在尝试从相对路径中获取样式表和 javascript 文件,因为您在index.html
:
<script src="/static/js/1.f9c0bd2f.chunk.js"></script>
由于您使用 Django 来收集静态文件,因此您还可以使用它的模板标签来引用模板中的静态文件:
<script src="{% static 'js/1.f9c0bd2f.chunk.js' %}"></script>
推荐阅读
- php - 如何使用 DOMDocument 从解析的 HTML 中删除内部 HTML?
- python - 在 django 中组织 url
- javascript - 为什么 jquery animate 仅适用于 Carousel Slider 中的第一个元素?
- ruby-on-rails - 清理视图中的参数
- r - 无法理解 predict() 在这种情况下的作用
- r - 如何在 R 中合并两个 .rda 文件?
- c# - 作为参数发送给重载函数时,子类可以向下转换吗
- python - 如何在没有硬核的python的turtle模块中制作多个按钮
- spring - ElasticsearchItemReader 不断读取相同的记录
- javascript - 如何通过两种方式数据绑定以在 Bootstrap 中动态设置滑动切换?