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

gdg*_*gdg 5 django url port nginx docker

  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"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

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

"image_url": "http://0.0.0.0:1337/mediafiles/publisher/sample-image4.jpg",
Run Code Online (Sandbox Code Playgroud)

更多细节

堆:

  • Ubuntu
  • Docker(组合)
  • nginx
  • 独角兽 19.9.0
  • Django 2.1.7
  • Django REST 框架 3.9.2
  • 蟒蛇 3+
  • Postgres/psycopg2

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

http://0.0.0.0:1337/mediafiles/publisher/sample-image4.jpg
Run Code Online (Sandbox Code Playgroud)

我不确定这是 nginx 问题、Django 设置问题还是我的代码是如何配置的。我无法通过 Google 找到任何其他报告的案例(可能是因为我还是 Django 的新手,尽管遵循了以下教程,但不确定配置是否正确)。

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

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

模型.py

{
    "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"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

序列化程序.py

"image_url": "http://0.0.0.0:1337/mediafiles/publisher/sample-image4.jpg",
Run Code Online (Sandbox Code Playgroud)

网址.py

http://0.0.0.0:1337/mediafiles/publisher/sample-image4.jpg
Run Code Online (Sandbox Code Playgroud)

视图.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})
Run Code Online (Sandbox Code Playgroud)

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:
Run Code Online (Sandbox Code Playgroud)

配置文件

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

gdg*_*gdg 12

由于这个略有不同的问题,我终于找到了如何修复图像 URL 。

解决方案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;
    }
Run Code Online (Sandbox Code Playgroud)

解决方案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;
    }
Run Code Online (Sandbox Code Playgroud)

在任一情况下,图像 URL 现在由 DRF 返回如下(图像链接)。

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"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

  • 或许,是的。当我开始构建这个时,我遵循了各种教程,这就是他们正在做的事情。所以这个答案更多的是关于“如何”而不是最佳实践。谢谢你提出来。 (2认同)