Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django压缩器:如何写入S3,从CloudFront读取?_Python_Django_Amazon S3_Amazon Cloudfront_Django Compressor - Fatal编程技术网

Python Django压缩器:如何写入S3,从CloudFront读取?

Python Django压缩器:如何写入S3,从CloudFront读取?,python,django,amazon-s3,amazon-cloudfront,django-compressor,Python,Django,Amazon S3,Amazon Cloudfront,Django Compressor,我想从CloudFront提供压缩后的CSS/JS(它们位于S3上),但无法通过settings.py中的compressor settings解决问题,我有以下几点: COMPRESS_OFFLINE = True COMPRESS_URL = 'http://static.example.com/' #same as STATIC_URL, so unnecessary, just here for simplicity COMPRESS_STORAGE = 'my

我想从CloudFront提供压缩后的CSS/JS(它们位于S3上),但无法通过settings.py中的compressor settings解决问题,我有以下几点:

    COMPRESS_OFFLINE = True 
    COMPRESS_URL = 'http://static.example.com/' #same as STATIC_URL, so unnecessary, just here for simplicity
    COMPRESS_STORAGE = 'my_example_dir.storage.CachedS3BotoStorage' #subclass suggested in [docs][1]
    COMPRESS_OUTPUT_DIR = 'compressed_static'
    COMPRESS_ROOT = '/home/dotcloud/current/static/' #location of static files on server
尽管有压缩URL,我的文件仍从s3存储桶中读取:


我想问题是我想将文件写入S3,但从CloudFront读取它。这可能吗?

我围绕boto提供的后端编写了一个包装存储后端

myapp/storage_backends.py:

import urlparse
from django.conf import settings
from storages.backends.s3boto import S3BotoStorage

def domain(url):
    return urlparse.urlparse(url).hostname    

class MediaFilesStorage(S3BotoStorage):
    def __init__(self, *args, **kwargs):
        kwargs['bucket'] = settings.MEDIA_FILES_BUCKET
        kwargs['custom_domain'] = domain(settings.MEDIA_URL)
        super(MediaFilesStorage, self).__init__(*args, **kwargs)

class StaticFilesStorage(S3BotoStorage):
    def __init__(self, *args, **kwargs):
        kwargs['bucket'] = settings.STATIC_FILES_BUCKET
        kwargs['custom_domain'] = domain(settings.STATIC_URL)
        super(StaticFilesStorage, self).__init__(*args, **kwargs)
my settings.py文件的位置

STATIC_FILES_BUCKET = "myappstatic"
MEDIA_FILES_BUCKET = "myappmedia"
STATIC_URL = "http://XXXXXXXX.cloudfront.net/"
MEDIA_URL = "http://XXXXXXXX.cloudfront.net/"

DEFAULT_FILE_STORAGE = 'myapp.storage_backends.MediaFilesStorage'
COMPRESS_STORAGE = STATICFILES_STORAGE = 'myapp.storage_backends.StaticFilesStorage'

我对settings.py做了一些不同的更改

AWS_S3_CUSTOM_DOMAIN = 'XXXXXXX.cloudfront.net' #important: no "http://"
AWS_S3_SECURE_URLS = True #default, but must set to false if using an alias on cloudfront

COMPRESS_STORAGE = 'example_app.storage.CachedS3BotoStorage' #from the docs (linked below)
STATICFILES_STORAGE = 'example_app.storage.CachedS3BotoStorage'
AWS_IS_GZIPPED = True

上述解决方案将文件保存在本地,并将其上载到s3。这让我可以脱机压缩文件。如果您不是gzipping,以上内容应该适用于从CloudFront提供压缩文件

添加gzip会增加皱纹:

设置.py

AWS_S3_CUSTOM_DOMAIN = 'XXXXXXX.cloudfront.net' #important: no "http://"
AWS_S3_SECURE_URLS = True #default, but must set to false if using an alias on cloudfront

COMPRESS_STORAGE = 'example_app.storage.CachedS3BotoStorage' #from the docs (linked below)
STATICFILES_STORAGE = 'example_app.storage.CachedS3BotoStorage'
AWS_IS_GZIPPED = True
尽管这会导致在静态收集过程中将可压缩文件(根据存储的css和js)推送到s3时出错:

AttributeError:'cStringIO.StringO'对象没有属性'name'

这是由于一些奇怪的错误,与css/js文件的压缩有关,我不理解。我需要的这些文件是本地的、解压缩的,而不是s3上的,因此如果我调整上面引用的存储子类(并在压缩程序中提供),我可以完全避免这个问题

新存储.py

from os.path import splitext 
from django.core.files.storage import get_storage_class  
from storages.backends.s3boto import S3BotoStorage  


class StaticToS3Storage(S3BotoStorage): 

    def __init__(self, *args, **kwargs): 
        super(StaticToS3Storage, self).__init__(*args, **kwargs) 
        self.local_storage = get_storage_class('compressor.storage.CompressorFileStorage')() 

    def save(self, name, content): 
        ext = splitext(name)[1] 
        parent_dir = name.split('/')[0] 
        if ext in ['.css', '.js'] and not parent_dir == 'admin': 
            self.local_storage._save(name, content) 
        else:     
            filename = super(StaticToS3Storage, self).save(name, content) 
            return filename 
然后,它保存了所有的.css和.js文件(不包括管理文件,我从CloudFront提供未压缩的管理文件),同时将其余的文件推送到s3(并且不用费心在本地保存它们,不过可以很容易地添加self.local_存储。_保存行)

但当我运行compress时,我希望压缩后的.js和.css文件被推送到s3,因此我创建了另一个子容器供compressor使用:

class CachedS3BotoStorage(S3BotoStorage): 
        """ 
        django-compressor uses this class to gzip the compressed files and send them to s3 
        these files are then saved locally, which ensures that they only create fresh copies 
        when they need to 
        """ 
        def __init__(self, *args, **kwargs): 
            super(CachedS3BotoStorage, self).__init__(*args, **kwargs) 
            self.local_storage = get_storage_class('compressor.storage.CompressorFileStorage')() 


        def save(self, filename, content): 
            filename = super(CachedS3BotoStorage, self).save(filename, content) 
            self.local_storage._save(filename, content) 
            return filename 
最后,考虑到这些新的子类,我需要更新一些设置:

COMPRESS_STORAGE = 'example_app.storage.CachedS3BotoStorage' #from the docs (linked below)
STATICFILES_STORAGE = 'example_app.storage.StaticToS3Storage'

这就是我要说的。

看起来问题实际上是在Django上游解决的

有问题的get_size方法可能会在本地进行修补,以解决Django旧版本的问题


编辑:查看实际解决方法。

实际上,这似乎也是django存储中的一个问题。当compressor比较S3上文件的散列时,django storages不会解压缩Gzip文件的内容,而是尝试比较不同的散列。我已经准备好了


FWIW,它还修复了另一个问题,即当AWS__gzip设置为True时,实际将文件保存到S3。这真是一只牦牛。

此外,对于流媒体发行版,重写
url
函数以允许
rtmp://
url非常有用,如:

import urlparse
class VideoStorageForCloudFrontStreaming(S3BotoStorage):
    """
    Use when needing rtmp:// urls for a CloudFront Streaming distribution. Will return
    a proper CloudFront URL.

    Subclasses must be sure to set custom_domain.
    """
    def url(self, name):
        name = urlparse.quote(self._normalize_name(self._clean_name(name)))
        return "rtmp://%s/cfx/st/%s" % (self.custom_domain, name)

    # handy for JW Player:
    @Property
    def streamer(self):
        return "rtmp://%s/cfx/st" % (self.custom_domain)

看起来CloudFront现在提供了内置的压缩功能。如果启用,则向CloudFront发出请求。如果CF没有存储压缩的缓存版本,它会向原始服务器(S3)发出请求,原始服务器返回未压缩的文件。CloudFront随后将自动压缩文件,将其存储在缓存中,并将其提供给查看器

通过编辑发行版中的“行为”,可以在CF中启用自动压缩。在底部,它会询问“自动压缩文件”,您可以将其另存为“是”

对此的p.S.要求:


在权限中,更改CORS以显示内容长度,即

在github上看到您的票证。。。你介意发布你的解决方案吗?我为没有早点看到这一点表示诚挚的歉意,我明天会在下面发布我的解决方案(希望如此)。另一个窍门是转到你的CloudFront发行版>“编辑”行为>,并在底部显示“自动压缩对象”的地方单击“是”并保存。我会尽快查看@jiao。我已经实现了我自己的黑客解决方案,但我将对照我的解决方案进行检查,看看它是如何工作的。我一确认就会回来给你检查!不管怎样,谢谢。这项工作给了我递归深度的错误。我刚刚复制粘贴了你的补丁,将默认的存储类更改为新的,并打开了AWS_is_gzip标志。我也有同样的问题,有没有关于它的原因或自它工作以来发生了什么变化的消息?谢谢你的提示!