当Django中的DEBUG为False时,静态文件无法被访问。

3
我使用Docker Compose,结合这个Dockerfile将static文件夹复制到/static目录下:
FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY static /static/
COPY . /code/

在我的设置文件中,我使用:

if env == "dev":
    DEBUG = True
else:
    DEBUG = False
    SECURE_CONTENT_TYPE_NOSNIFF = True
    SECURE_BROWSER_XSS_FILTER = True
    X_FRAME_OPTIONS = "DENY"

STATICFILES_FINDERS = [
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]

STATICFILES_DIRS = [
    # os.path.join(BASE_DIR, "static/"),
    '/static'
]

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'

在开发环境下静态文件能正常工作,但当我将环境切换到生产环境时,出现了404错误。

您看到问题了吗?


1
Django的静态文件在生产环境中无法正常工作(https://docs.djangoproject.com/en/2.2/howto/static-files/#serving-static-files-during-development),因此最好为此配置nginx/apache/...。 - Willem Van Onsem
2
请参考以下链接:https://docs.djangoproject.com/en/2.2/howto/static-files/deployment/ - Willem Van Onsem
STATICFILES_DIRS 是您的静态文件在代码仓库内的位置,Django 应该从中获取它们以进行 collectstatic。因此,该设置是错误的,它不应该是 /static(通常,如果在应用程序的“静态”文件夹中,则根本不需要设置此项)。同时请向我们展示您的 Apache/Nginx 配置。 - dirkgroten
注意:我已经写了一篇关于如何使用whitenoise和CDN(针对AWS,但包含有用的解释,帮助您理解整个过程)设置静态文件的博客文章 - dirkgroten
2个回答

4

注意:这个答案也是正确的,但我也接受了上面的答案(因为我的应用程序将接收非常低的流量)。

谢谢你的评论,它们很有用。

这是我的新Docker Compose文件:

version: '3.5'

services:
  nginx:
    image: nginx:latest
    ports:
      - "8002:8000"
    volumes:
      - $PWD:/code
      - ./config/nginx:/etc/nginx/conf.d
      - ./static:/static
    depends_on:
      - web
    networks:
      - my_net
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    env_file: .env
    volumes:
      - $PWD:/code
      - ./static:/static
    expose:
      - "8000"
    networks:
      - my_net

networks:
  my_net:
    driver: bridge

以下是Nginx配置文件:

upstream web {
  ip_hash;
  server web:8000;
}

server {

    location /static/ {
        autoindex on;
        alias /static/;
    }

    location / {
        proxy_pass http://web/;
    }
    listen 8000;
    server_name localhost;
}

您应该将“web”添加到允许的主机列表中:
ALLOWED_HOSTS = ['0.0.0.0', 'localhost', 'web']

更新: settings.py文件:
STATICFILES_FINDERS = [
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
    # '/static'
]

STATIC_ROOT = '/static' #os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'

正如@dirkgroten所说,您可以在提供的静态文件中设置到期标头。

另一个解决方案是使用Whitenoise(感谢Daniel Roseman)。


为了完整性,请展示你的设置(STATIC_ROOT 应该是 '/static',而 STATICFILES_DIRS 应该是 os.path.join(BASE_DIR, "static") 或者如果你的静态文件在应用程序的静态目录中,则为空)。 - dirkgroten
另外,正如我在博客文章中提到的那样,如果您使用nginx来提供静态文件,则应设置到期标头,以便用户不必为每个页面下载它们。并且您应该使用不同的STATICFILES_STORAGE来添加清单。 - dirkgroten

3

虽然强烈不建议在Django中生产环境中提供静态文件(有非常充分的理由),但是我经常需要这样做。

在某些情况下这是完全可以接受的(低流量,仅用于REST API的服务器等)。如果您需要这样做,此代码片段应该会有所帮助。根据您的Django版本调整re_path或使用url()

from django.contrib.staticfiles.views import serve as serve_static

def _static_butler(request, path, **kwargs):
    """
    Serve static files using the django static files configuration
    WITHOUT collectstatic. This is slower, but very useful for API 
    only servers where the static files are really just for /admin

    Passing insecure=True allows serve_static to process, and ignores
    the DEBUG=False setting
    """
    return serve_static(request, path, insecure=True, **kwargs)

urlpatterns = [
    ...,
    re_path(r'static/(.+)', _static_butler)
]


不确定为什么我的资产出现“服务器错误(500)”。 - 4m1nh4j1
谢谢,它有效。我会接受这个答案,但是对于那些正在寻找使用docker-compose和nginx的解决方案的人来说,我写的另一个解决方案也同样有效。 - 4m1nh4j1
1
说实话,我觉得你的解决方案更好!我的有点像是一个hack,并不是真正的“解决方案”。它只有在某些特定情况下才适用。 - Andrew
我更新了我的回复并提到了低流量情况。 - 4m1nh4j1
没有必要这样做。如果你想从Django提供静态文件,请使用Whitenoise。 - Daniel Roseman
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接