Django-Ngix-Gunicorn 使用 Docker Compose 返回错误的媒体文件路径

标签 django nginx django-rest-framework docker-compose gunicorn

我在使用 docker compose 在生产模式下部署 Django REST Framework 应用程序时遇到问题。问题是当我的端点返回带有 ImageField 的模型时,它返回错误的路径,特别是缺少 url 端口。静态文件可以与响应 URL 中包含的端口正常工作。

例如:

当前值:http://127.0.0.1/media/machines/034793bb-8516-45e3-a50a-4e00e7488617.png

预期:http://127.0.0.1:8000/media/machines/034793bb-8516-45e3-a50a-4e00e7488617.png

Settings.py

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
TEMPLATE_DIR = os.path.join(BASE_DIR, 'templates')
STATIC_DIR = os.path.join(BASE_DIR,'static')
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 
MEDIA_URL = '/media/'

STATIC_URL = '/static/'
STATIC_ROOT = '/app/static/'

** Docker 文件 **

FROM python:3.6
ENV PYTHONUNBUFFERED 1
RUN mkdir /app
WORKDIR /app
ADD . /app/
RUN pip install -r requirements.txt

CMD ["gunicorn", "-c", "config/gunicorn/conf.py", "--bind", ":8000", "--chdir", 
"app_api.wsgi:application"]

Docker-compose

version: '3.7'

services:
  web-service:
    build: .
    command: bash -c "pip install -r requirements.txt && python manage.py makemigrations && python 
    manage.py migrate && python manage.py collectstatic --noinput && python manage.py runserver 
    0.0.0.0:8000"
    container_name: app_backend
    volumes:
      - static:/app/static
      - media:/app/media
      - .:/app
    depends_on: 
      - db
    restart: on-failure:2
  db:
    image: postgres
    container_name: app_postgres
    environment: 
      - POSTGRES_USER=bd_user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=new_database
    ports: 
      - "5432:5432"
    volumes: 
      - postgres:/var/lib/postgresql/data
    restart: on-failure:2
  nginx:
    image: nginx:latest
    ports:
      - 8000:80
    volumes: 
      - ./config/nginx/conf.d:/etc/nginx/conf.d
      - static:/app/static
      - media:/app/media
    depends_on: 
      - web-service
volumes:
  media:
  static:
  postgres: 
    driver: local 

Nginx 配置文件

upstream django_server {
    server web-service:8000;
}

server {
    listen 80;
    server_name localhost;

    location /static/ {
        alias /app/static/;
    }

    location /media/ {
        alias /app/media/;
    }

    location / {
        proxy_pass http://django_server;
        proxy_set_header X-Fowarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }
}

** Gunicorn 配置 **

name = 'docker_django'
loglevel = 'info'
errorlog = '-'
accesslog = '-'
workers = 2

型号

class Machine(models.Model):
    name = models.CharField(max_length=100, blank=False, null=False)
    description = models.CharField(max_length=250, blank=True, null=True)
    image = models.ImageField(upload_to = 'machines', default='default.png')
    provider = models.TextField(blank=True, null=True)
    model = models.CharField(max_length=250, blank=True, null=True)
    data_source = models.ForeignKey(DataSource, related_name='data_source', on_delete=models.CASCADE)

    def __str__(self):
        return self.name

最佳答案

最简单的选择是在 nginx 中使用 $http_host 而不是 $host,因为 $host 不包含端口信息。但是,某些客户端的 $http_host 可能为空。

        proxy_set_header Host $host;

Differences described in this SO answer

由于 nginx 对 8000 端口一无所知,因此它暴露在 docker 主机上,因此无法对其进行设置。一种选择是从请求中获取 Host http header (在请求中可能不存在,可能在极少数情况下)。

另一个选项是将 nginx 端口作为环境变量公开传递到 nginx 容器中,并在附加到 $host 的配置中使用此变量,对于 nginx 可以使用 envsubst 来完成> 在自定义入口点中运行。

它适用于静态文件的原因 - 静态文件 URL 包含在模板(而不是 API 响应)中,并带有相对于当前网站根目录(无论它是什么)的链接,并且它们不需要 build_absolute_uri() 由 django 运行。

关于Django-Ngix-Gunicorn 使用 Docker Compose 返回错误的媒体文件路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61599811/

相关文章:

Django 无法在 Ubuntu 上加载 SpatiaLite 库扩展 mod_spatialite

python - “用户”对象不支持索引

visual-studio - 使用Visual Studio编译NGINX

Nginx HTTP 基本身份验证,特定 IP 地址异常(exception)

django - 嵌套网址不适用于 Django REST 框架

python - Django:列表显示管理中的外键值

django - 覆盖 django-allauth 的默认模板

laravel - 为什么 laravel ubuntu 服务器占用这么多硬盘空间

Django-rest-framework + React-Admin : URL Backslash issue

python - Django Rest Framework - 测试客户端发布整数列表