0

我已经构建了一个仅提供 JSON 响应的 Django REST API。我的问题是,在生产中(使用 debug=False 部署在 Heroku 上),该应用程序似乎没有提供适当的管理界面样式所需的相关静态文件(仅用于静态文件的用例)。请注意,在开发中(带有 debug=True 的 localhost),管理界面的样式正确。

转到已部署(Heroku)地址的管理路由,内容已交付,但没有任何样式。浏览器开发人员工具指示由于 500 错误代码而无法加载样式表。Django 日志输出显示以下详细信息。

django.request ERROR    Internal Server Error: /static/admin/css/base.1f418065fc2c.css
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/app/secure_my_spot/custom_middleware/request_logging.py", line 30, in __call__
print(f"Content: {response.content}")
File "/usr/local/lib/python3.8/site-packages/django/http/response.py", line 407, in content
raise AttributeError(
AttributeError: This WhiteNoiseFileResponse instance has no `content` attribute. Use `streaming_content` instead.

我已经进入 Heroku dyno 并验证了导致 500 错误的静态文件实际上根据 Django 的 settings.py 位于 static_root 中。我一直在花费大量时间在互联网上搜索可能导致文件无法在生产中提供的线索,但无论我尝试过什么,它都不起作用。

以下是相关文件和设置的精选摘要。

Dockerfile

FROM python:3.8-alpine

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

RUN apk update && apk add \
    gcc \
    libc-dev \
    python3-dev \
    musl-dev \
    postgresql-dev \
    vim \
    bash --no-cache --upgrade

RUN pip install \
    pipenv \
    psycopg2

COPY Pipfile Pipfile.lock ./

RUN pipenv install --system --deploy --pre

COPY . .

RUN python manage.py collectstatic --noinput

CMD gunicorn secure_my_spot.wsgi:application --bind 0.0.0.0:$PORT

heroku.yml

build:
  docker:
    web: Dockerfile
release:
  image: web
  command:
    - chmod u+x heroku_entrypoint.sh
run:
  web: ./heroku_entrypoint.sh

heroku_entrypoint.sh

#!/bin/bash

python manage.py collectstatic --noinput
python manage.py migrate --noinput
gunicorn secure_my_spot.wsgi:application --bind 0.0.0.0:$PORT

设置.py

BASE_DIR = Path(__file__).resolve().parent.parent

INSTALLED_APPS = [
    "django_extensions",
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "rest_framework",
    "rest_framework.authtoken",
    "app",
    "corsheaders",
]

MIDDLEWARE = [
    "corsheaders.middleware.CorsMiddleware",
    "secure_my_spot.custom_middleware.request_logging.RequestLogging",
    "django.middleware.security.SecurityMiddleware",
    "whitenoise.middleware.WhiteNoiseMiddleware",
    "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",
]

STATIC_URL = "/static/"

STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles/")

STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)

STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"

wsgi.py

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "secure_my_spot.settings")

if settings.DEBUG:
    application = StaticFilesHandler(get_wsgi_application())
else:
    application = get_wsgi_application()
4

1 回答 1

0

阅读完这篇文章后,我将 Django SecurityMiddleware 移到了中间件数组的顶部,紧随其后的是 WhiteNoiseMiddleware(见下文)。这个小改动起到了作用,所有静态资产现在都按预期提供。

设置.py

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "whitenoise.middleware.WhiteNoiseMiddleware",
    "corsheaders.middleware.CorsMiddleware",
    "secure_my_spot.custom_middleware.request_logging.RequestLogging",
    "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",
]

不幸的是,我没有很好的解释为什么仅仅改变中间件数组元素的顺序会导致这个问题。即使错误消息未指示任何 CORS 错误,在 CorsMiddleware 之前移动 WhiteNoiseMiddleware 也可能很重要。

于 2021-10-05T13:38:06.977 回答