18

圧縮された CSS/JS を CloudFront から提供したい (それらは S3 上にある) のですが、settings.py のコンプレッサー設定を介してそれを行う方法がわかりません。

    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

COMPRESS_URL にもかかわらず、私のファイルは私の s3 バケットから読み取られています:
<link rel="stylesheet" href="https://example.s3.amazonaws.com/compressed_static/css/e0684a1d5c25.css?Signature=blahblahblah;Expires=farfuture;AWSAccessKeyId=blahblahblah" type="text/css" />

問題は、ファイルを S3 に書き込みたいのですが、CloudFront から読み取ることだと思います。これは可能ですか?

4

6 に答える 6

33

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)

私の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'
于 2012-01-17T02:22:33.250 に答える
11

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'

コンプレッサーのドキュメント

この上記のソリューションでは、ファイルをローカルに保存し、s3 にアップロードしました。これにより、ファイルをオフラインで圧縮できます。gzip を使用していない場合、上記は CloudFront から圧縮ファイルを提供するために機能するはずです。

gzip を追加すると、しわが追加されます。

設定.py

AWS_IS_GZIPPED = True

これにより、collectstatic 中に圧縮可能なファイル (ストレージに応じて css および js) が s3 にプッシュされるたびにエラーが発生しました。

AttributeError: 'cStringIO.StringO' オブジェクトに属性 'name' がありません

これは、私が理解していない css/js ファイルの圧縮に関係するいくつかの奇妙なエラーが原因でした。これらのファイルは、s3 ではなく、ローカルで解凍する必要があるため、上記で参照したストレージ サブクラスを微調整すれば、問題を完全に回避できます (コンプレッサーのドキュメントで提供されます)。

新しい storage.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_storage を簡単に追加できます)。 _保存行)。

しかし、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'

そして、それについて私が言わなければならないのはそれだけです。

于 2012-01-24T05:00:16.410 に答える
4

問題は実際に Django のアップストリームで修正されたようです

問題のある _get_size メソッドは、ローカルでパッチを適用して、古いバージョンの Django で回避できる可能性があります。

編集:実際の回避策については、https://github.com/jezdez/django_compressor/issues/100を参照してください。

于 2012-05-03T16:12:22.613 に答える
3

実際、これは django-storages の問題でもあるようです。コンプレッサが S3 上のファイルのハッシュを比較するとき、django-storages は Gzip されたファイルのコンテンツを解凍しませんが、異なるハッシュを比較しようとします。それを修正するためにhttps://bitbucket.org/david/django-storages/pull-request/33/fix-gzip-supportを開きました。

FWIW、https://bitbucket.org/david/django-storages/pull-request/32/s3boto-gzip-fix-and-associated-unit-testsもあり、実際に S3 にファイルを保存するときに別の問題を修正しますAWS_IS_GZIPPED を True に設定。なんとヤクでした。

于 2012-05-10T10:26:03.413 に答える
1

さらに、ストリーミング配信の場合、次のように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)
于 2012-07-01T21:34:45.597 に答える