在图片的url中获取两个“https://”

问题描述 投票:0回答:1

我正在使用 Django 和 Django Rest Framework 开发一个项目,其中我必须在模型中保存图像。我使用 S3 存储桶作为存储设备。我可以上传图像并将其保存到模型中。

问题

当获取响应(获取单个对象或对象数组)时,我得到带有两个

https://
的图像的 url。仅当我使用 AWS Ec2 上的
hosted
的 Django 服务器时,才会发生这种情况。使用
localhost
时图像的url会正常返回,问题也出在静态文件上(但它们没有被使用,只有管理面板和rest-framework模板使用它)

示例:

从托管服务器调用 API 时

这是回应。请注意 image 字段。

[
    {
        "id": 5,
        "image": "https://https://d2to87w45k79nd.cloudfront.net/media/testimonies/Myron/Section_2_img.png",
        "name": "Myron",
        "message": "Cool Website",
        "position": "CEO",
        "company": "ME Ltd."
    },
    {
        "id": 6,
        "image": "https://https://d2to87w45k79nd.cloudfront.net/media/testimonies/phoenix0347/Section_2_img.png",
        "name": "phoenix0347",
        "message": "askjn",
        "position": "false",
        "company": "false"
    },
    {
        "id": 7,
        "image": "https://https://d2to87w45k79nd.cloudfront.net/media/testimonies/Kushagra%20Gupta/Section_9.png",
        "name": "Kushagra Gupta",
        "message": "jksabdsadb",
        "position": "1jb",
        "company": "sajd"
    },
    {
        "id": 8,
        "image": "https://https://d2to87w45k79nd.cloudfront.net/media/testimonies/jksadb/hero_img.png",
        "name": "jksadb",
        "message": "akjsbasjdb",
        "position": "213u3",
        "company": "129ujieo2"
    }
]

从本地主机调用时相同的 API 给出

这样的回应。再次注意image字段!

[
    {
        "id": 5,
        "image": "https://d2to87w45k79nd.cloudfront.net/media/testimonies/Myron/Section_2_img.png",
        "name": "Myron",
        "message": "Cool Website",
        "position": "CEO",
        "company": "ME Ltd."
    },
    {
        "id": 6,
        "image": "https://d2to87w45k79nd.cloudfront.net/media/testimonies/phoenix0347/Section_2_img.png",
        "name": "phoenix0347",
        "message": "askjn",
        "position": "false",
        "company": "false"
    },
    {
        "id": 7,
        "image": "https://d2to87w45k79nd.cloudfront.net/media/testimonies/Kushagra%20Gupta/Section_9.png",
        "name": "Kushagra Gupta",
        "message": "jksabdsadb",
        "position": "1jb",
        "company": "sajd"
    },
    {
        "id": 8,
        "image": "https://d2to87w45k79nd.cloudfront.net/media/testimonies/jksadb/hero_img.png",
        "name": "jksadb",
        "message": "akjsbasjdb",
        "position": "213u3",
        "company": "129ujieo2"
    }
]

我不知道是什么导致了这个问题...我正在使用 boto3、django-storages python 包来实现 S3 中的存储。

我正在提供我的

settings.py
storages.py
views.py
serializers.py

settings.py

# Static files (CSS, JavaScript, Images)
USE_S3 = not DEBUG

if USE_S3:  # In Production Use CDN(Amazon CloudFront in this case)
    # AWS Settings
    AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_ID')
    AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_KEY')
    AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_S3_BUCKET_NAME')
    AWS_DEFAULT_ACL = None
    AWS_CLOUDFRONT_DOMAIN = os.getenv('AWS_CLOUDFRONT_DOMAIN')
    AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'}

    # s3 static settings
    STATIC_LOCATION = 'static'
    STATIC_URL = f'https://{AWS_CLOUDFRONT_DOMAIN}/{STATIC_LOCATION}/'
    STATICFILES_STORAGE = 'backend.storage_backends.StaticStorage'

    # media settings
    PUBLIC_MEDIA_LOCATION = 'media'
    MEDIA_URL = f'{AWS_CLOUDFRONT_DOMAIN}/{PUBLIC_MEDIA_LOCATION}/'
    DEFAULT_FILE_STORAGE = 'backend.storage_backends.MediaStorage'
else:  # In Development use local storage (I can also use s3 if I wish to in development by setting DEBUG to false)
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

storages.py

from django.conf import settings
from storages.backends.s3boto3 import S3Boto3Storage


class StaticStorage(S3Boto3Storage):
    location = settings.STATIC_LOCATION
    default_acl = settings.AWS_DEFAULT_ACL

    def __init__(self, **kwargs):
        kwargs['custom_domain'] = settings.AWS_CLOUDFRONT_DOMAIN
        super(StaticStorage, self).__init__(**kwargs)


class MediaStorage(S3Boto3Storage):
    location = settings.PUBLIC_MEDIA_LOCATION
    default_acl = settings.AWS_DEFAULT_ACL
    file_overwrite = False

    def __init__(self, **kwargs):
        kwargs['custom_domain'] = settings.AWS_CLOUDFRONT_DOMAIN
        super(MediaStorage, self).__init__(**kwargs)

serializer.py

from rest_framework import serializers

from .models import Testimonies


class TestimonySerializer(serializers.ModelSerializer):
    image = serializers.ImageField()

    @staticmethod
    def get_image(instance):
        try:
            print(instance.image.url)
            return instance.image.url
        except Exception as e:
            print(e)
            return ''

    class Meta:
        model = Testimonies
        fields = '__all__'

views.py

from rest_framework import status
from rest_framework.generics import GenericAPIView
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response

from .serializers import TestimonySerializer
from .models import Testimonies


class Testimony(GenericAPIView):
    serializer_class = TestimonySerializer
    queryset = Testimonies.objects.all()
    lookup_field = 'id'
    parser_classes = [MultiPartParser, FormParser]

    def get(self, req, *args, **kwargs):
        # Get single Testimony
        if 'id' in kwargs:
            testimony = self.get_object()
            serializer = self.get_serializer(testimony)
            return Response(serializer.data, status=status.HTTP_200_OK)

        # Get All Testimonies
        testimonies = self.get_queryset()
        serializer = self.get_serializer(testimonies, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def post(self, req, **kwargs):
        data = self.request.data

        try:
            serializer = self.get_serializer(data=data)
            serializer.is_valid(raise_exception=True)
            serializer.save()

            res = {
                "message": "Testimony Added Successfully",
                "success": True
            }
            return Response(res, status=status.HTTP_201_CREATED)
        except Exception as e:
            print(e)
            res = {
                "message": "Something went wrong",
                "success": False,
                "error": str(e),
            }
            return Response(res, status=status.HTTP_400_BAD_REQUEST)

models.py

from django.db import models


def set_image_path(instance, filename):
    return f"testimonies/{instance.name}/{filename}"


class Testimonies(models.Model):
    name = models.CharField(max_length=200)
    message = models.TextField()

    image = models.ImageField(upload_to=set_image_path)

    position = models.CharField(max_length=200)
    company = models.CharField(max_length=300)

    def __str__(self):
        return self.name

请帮我解决这个问题!这是我第一次在生产中遇到此类错误...非常感谢您的时间和见解!!

  1. 我尝试使用
    SerializerMethodField
    作为
    serializers.py
    中的图像字段,但我无法上传图像。
  2. 我尝试更改
    MEDIA_URL
     中的 
    settings.py
  3. 我尝试查看库的代码,在那里我看到它确实添加了
    https://
    ,但它将它添加到我在
    custom_domain
    中设置为
    storages.py
    CLOUDFRONT_DOMAIN
    之前。我也会将库中的特定代码粘贴到此处。
    def url(self, name, parameters=None, expire=None, http_method=None):
        # Preserve the trailing slash after normalizing the path.
        name = self._normalize_name(clean_name(name))
        params = parameters.copy() if parameters else {}
        if expire is None:
            expire = self.querystring_expire

        if self.custom_domain:
            url = "{}//{}/{}{}".format(
                self.url_protocol,
                self.custom_domain,
                filepath_to_uri(name),
                "?{}".format(urlencode(params)) if params else "",
            )

            if self.querystring_auth and self.cloudfront_signer:
                expiration = datetime.utcnow() + timedelta(seconds=expire)
                return self.cloudfront_signer.generate_presigned_url(
                    url, date_less_than=expiration
                )

            return url

这就是我所尝试的一切,它没有在本地主机上显示它,但问题仍然存在于生产服务器上。

我的前端托管在 vercel 上。虽然我不认为这是一个问题,因为响应本身有缺陷,所以前端没有对它做任何事情,我确信这一点!

python django django-rest-framework boto3 django-storage
1个回答
0
投票

你的静态网址应该是这样的

STATIC_URL = f'{AWS_CLOUDFRONT_DOMAIN}/{STATIC_LOCATION}/'
© www.soinside.com 2019 - 2024. All rights reserved.