【问题标题】:Flask static_folder hosted on S3Flask static_folder 托管在 S3 上
【发布时间】:2012-02-25 04:58:45
【问题描述】:
我正在尝试将我的所有 /static 内容重新路由到 Amazon S3 上的主机。我的第一个想法是在我的 jinja 模板中使用 global config['path'] ,但这不适用于外部 css 和 js 文件,而且有点混乱。我找到了 0.7 中发布的 static_folder 和 static_url_path,这似乎是我想要的。但是,当我转到 http://localhost:8000/static/img/abc.jpg 时,它不会在 S3 上找到文件。我是否正确使用了此功能,还是有其他方法可以做到这一点?
谢谢!
【问题讨论】:
标签:
python
amazon-s3
flask
jinja2
【解决方案1】:
我最近开发了一个 Flask 扩展来处理这种情况。它被称为Flask-S3,你可以阅读它的文档here。
例如,以下是您将其集成到 Flask 应用程序中的方法:
from flask import Flask
from flask_s3 import FlaskS3
app = Flask(__name__)
app.config['S3_BUCKET_NAME'] = 'mybucketname'
s3 = FlaskS3(app)
您可以使用扩展程序将您的资产上传到您选择的存储桶:
>>> from my_application import app
>>> from flask_s3 import create_all
>>> create_all(app)
Flask-S3 可识别蓝图,并将上传与任何注册蓝图相关的所有资产。
【解决方案2】:
我希望 flask.Flask 构造函数的 static_url_path 参数能够接受完整的 URI,但是当您尝试这样做时,它会尖叫路径需要前导斜杠。如果它接受它,你可以在设置static_url_path='http://my_s3_bucket.aws.amazon.com/'左右之后使用url_for。
另一种可能的解决方案是使用上下文处理器。我相信这是最干净的解决方案,但我对烧瓶没有太多经验。它确实看起来干净。使用上下文处理器,我从环境中提取 URL(我正在使用 heroku,所以它很容易设置)。然后上下文处理器使 static_url 变量在我的模板中可用。
在 app.py 中:
# Environment has STATIC_URL='http://my_s3_bucket.aws.amazon.com/'
@app.context_processor
def inject_static_url():
"""
Inject the variable 'static_url' into the templates. Grab it from
the environment variable STATIC_URL, or use the default.
Template variable will always have a trailing slash.
"""
static_url = os.environ.get('STATIC_URL', app.static_url_path)
if not static_url.endswith('/'):
static_url += '/'
return dict(
static_url=static_url
)
在模板中:
<link rel="stylesheet" type="text/css" href="{{ static_url }}css/main.css" />
结果
<link rel="stylesheet" type="text/css" href="http://my_s3_bucket.aws.amazon.com/css/main.css" />
【解决方案3】:
我知道这是一个老问题,但这是我解决这个问题的方法。
- 以不同的名称导入 Flask 的
url_for 方法(例如,flask_url_for)
- 创建您自己的自定义
url_for 方法,该方法调用flask_url_for,然后使用字符串替换添加到您的 S3 存储桶 url。
我喜欢这个策略,因为它使用起来简单直观,界面和原来的url_for方法一模一样。
from flask import url_for as flask_url_for
from flask import current_app
PRODUCTION_URL = 'https://s3.amazonaws.com/MY-BUCKET-NAME'
def url_for(path, **kwargs):
url = flask_url_for(path, **kwargs)
if url.startswith("/static") and not current_app.debug:
url = url.replace("/static", "", 1)
return PRODUCTION_URL + url
return url
【解决方案4】:
你想要完成的是能够写作
{{ url_for(app.static, file='img/abc.jpg', _external=True) }}
并将该解析为 s3 中的 url?
我相信 static_folder 和 static_url_path 是设置好的,所以如果你调用
app = Application('app', static_folder='foo', static_url_path='bar')
然后去
上面的 url_for 会输出
http://localhost:8000/bar/img/abc.jpg,它会在文件系统中寻找static/img/abc.jpg。
我认为您想要做的可能是编写一个自定义过滤器,将您的路径转换为 s3 url,以便您可以拨打类似的电话
{{ 'img/abc.jpg'|s3_static_url }}
这里有一些文档:flask custom filters
【解决方案5】:
您需要的是 Amazon S3 公共文件 URL,而不是 http://localhost:8000/static/img/abc.jpg。如果它只是几个文件,可以使用完整的 URL 将它们硬编码到您的模板中,或者如果您将有一个本地版本进行测试并在生产站点上使用 S3(就像我们一样),那么您可以尝试以下方法。
在基本模板(其他模板继承)的顶部定义一个可能称为 STATIC_ROOT 的新变量,并将其用作文件路径前缀。
例如:
{% if app.debug %}
{% set STATIC_ROOT = url_for('static', filename='') %}
{% else %}
{% set STATIC_ROOT = 'http://s3.amazonaws.com/bucketname/' }
{% endif %}
当您可能在本地测试应用程序时,这将为您提供默认路径,并在生产时为您提供公共 S3 url(基于调试标志)。
使用它:
<script src="{{ STATIC_ROOT }}js/jquery.min.js">