如何在Django中输出资源URL中IP地址后面的端口?

问题描述 投票:0回答:2
  1. 如何将主机端口添加到序列化响应中的 URL 中? Django 目前提供的它们没有端口,因此链接已损坏。
  2. 或者,如果添加端口不是正确的方法,我该如何更改配置,以便在访问资源时不需要在 URL 中指定端口?

输出(image_url 字段中缺少端口“:1337”)

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 1,
            "user": 1,
            "title": "Post 1",
            "slug": "post1",
            "image_url": "http://0.0.0.0/mediafiles/publisher/sample-image4.jpg",
            "content": "First",
            "draft": false,
            "publish": "2019-04-26",
            "updated": "2019-04-26T22:28:35.034742Z",
            "timestamp": "2019-04-26T22:28:35.034795Z"
        }
    ]
}

“image_url”字段将无法正确链接,除非它包含如下端口:

"image_url": "http://0.0.0.0:1337/mediafiles/publisher/sample-image4.jpg",

更多详情

堆栈:

  • Ubuntu
  • Docker(撰写)
  • Nginx
  • Gunicorn 19.9.0
  • Django 2.1.7
  • Django REST 框架 3.9.2
  • Python 3+
  • Postgres/psycopg2

我正在使用 Django REST 框架返回序列化对象的列表。这些对象包含一个名为“image”的 FileField,我可以输出该图像的 URL。唯一的问题是,当我在浏览器的输出中单击该链接时,如果不手动在地址中添加服务器端口,则无法访问该资源,例如

http://0.0.0.0:1337/mediafiles/publisher/sample-image4.jpg

我不确定这是 nginx 问题、Django 设置问题还是我的代码配置方式问题。我无法通过 Google 找到任何其他报告的案例(可能是因为我对 Django 还很陌生,尽管有以下教程,但不确定配置是否正确)。

我尝试了一些这些解决方案,但它们不输出端口。

有这个问题,但我没有使用 ImageField,我想为我使用 FileField 的情况找到解决方案。对主要问题的评论表明也不需要添加端口,所以也许这是一个基础设施问题而不是 Django 问题?对此的指导会很棒。

模型.py

class Post(models.Model):
    class Meta:
        ordering = ('timestamp',)

    user = models.ForeignKey(User, on_delete=models.PROTECT)
    title = models.CharField(max_length=120)
    slug = models.SlugField(unique=True)
    image = models.FileField(upload_to='publisher/', null=True, blank=True)
    content = models.TextField()
    draft = models.BooleanField(default=False)
    publish = models.DateField(auto_now=False, auto_now_add=False)
    updated = models.DateTimeField(auto_now=True, auto_now_add=False)
    timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)

    def __str__(self):
        return self.title

    def __unicode__(self):
        return str(self.id)

    def get_absolute_url(self):
        return reverse("post:detail", kwargs={"slug":self.slug})

序列化器.py

class PostSerializer(serializers.ModelSerializer):
    image_url = serializers.SerializerMethodField()

    class Meta:
        model = Post
        fields = [
            'id',
            'user',
            'title',
            'slug',
            'image_url',
            'content',
            'draft',
            'publish',
            'updated',
            'timestamp',
        ]

    def get_image_url(self, post):
        request = self.context.get('request')
        if post.image and hasattr(post.image, 'url'):
            image_url = post.image.url
            return request.build_absolute_uri(image_url)
        else:
            return None

urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('blog/(?P<version>(v1|v2))/', include('blog.urls'))
    ]
...
    [
    url(r'^posts/$', PostListAPIView.as_view(), name='posts'),
    ]

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

views.py

class PostListAPIView(generics.ListAPIView):
    model = Post
    queryset = Post.objects.all()
    serializer_class = PostSerializer

docker-compose.yml

version: '3.7'

services:
  web:
    build: ./app
    command: gunicorn hello_django.wsgi:application --bind 0.0.0.0:8000
    volumes:
      - ./app/:/usr/src/app/
      - static_volume:/usr/src/app/staticfiles
      - media_volume:/usr/src/app/mediafiles
    ports:
      - "8000"
    env_file: ./app/.env
    environment:
      - DB_ENGINE=django.db.backends.postgresql
      - DB_USER
      - DB_PASSWORD
      - DB_HOST=db
      - DB_PORT=5432
      - DATABASE=postgres
    depends_on:
      - db
    networks:
      - backend

  db:
    image: postgres:10.7-alpine
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    networks:
      - backend

  nginx:
    build: ./nginx
    volumes:
      - static_volume:/usr/src/app/staticfiles
      - media_volume:/usr/src/app/mediafiles
    ports:
      - "1337:80"
    depends_on:
      - web
    networks:
      - backend

networks:
  backend:
    driver: bridge

volumes:
  postgres_data:
  static_volume:
  media_volume:

nginx.conf

upstream hello_django {
    server web:8000;
}

server {

    listen 80;

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

    location /staticfiles/ {
        alias /usr/src/app/staticfiles/;
    }

    location /mediafiles/ {
        alias /usr/src/app/mediafiles/;
    }

    location /favicon.ico {
        access_log off;
        log_not_found off;
    }
}
django docker url nginx port
2个回答
21
投票

我终于找到了如何修复图像 URL,这要归功于 this Question,它略有不同。

解决方案1

在 nginx 配置的 Host 标头中添加端口号,如下所示:

    location / {
        proxy_pass http://hello_django;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host:1337;                               <<------- HERE
        proxy_redirect off;
    }

解决方案2

将 nginx 配置中的 Host 标头更改为

http_host
,如下所示:

    location / {
        proxy_pass http://hello_django;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;                               <<------- HERE
        proxy_redirect off;
    }

无论哪种情况,DRF 现在都会按如下方式返回图像 URL(图像链接)。

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 2,
            "user": 1,
            "title": "First post",
            "slug": "first",
            "image_url": "http://0.0.0.0:1337/mediafiles/publisher/background.gif",    <----HERE
            "content": "Second post content.",
            "draft": false,
            "publish": "2019-05-22",
            "updated": "2019-05-22T09:41:36.257605Z",
            "timestamp": "2019-05-22T07:58:01.471534Z"
        }
    ]
}

0
投票

添加:

proxy_set_header Host $host:1337;
为我工作

© www.soinside.com 2019 - 2024. All rights reserved.