在生产中从 CDN 而不是 Flask 提供静态文件

Serve static files from a CDN rather than Flask in production

在我的 Flask 应用程序中,我通过开发环境中的应用程序提供静态资产,但我想在生产环境中使用 CDN。每个资产都加载到一个名为 base.html 的模板中,所以我想最简单的解决方案是将一个变量传递给渲染函数并在模板中使用它,如:

<script src="{{ STATIC_URL }}/js/main.js"></script>

通常在开发环境中为空字符串,在生产环境中为 cdn url。我想避免将此 STATIC_URL 变量传递给每个视图。我可以让它与

一起工作
@bp.context_processor
def set_static_path():
    return dict(STATIC_URL='https://foo.bar.com')

但对我来说这似乎有点老套。有没有更好的办法解决这个问题?

无需将 link 更改为静态文件,您仍然可以使用 url_for('static', filename='myfile.txt')。将默认静态视图替换为重定向到 CDN(如果已配置)的视图。

from urllib.parse import urljoin
# or for python 2: from urlparse import urljoin
from flask import redirect

@app.endpoint('static')
def static(filename):
    static_url = app.config.get('STATIC_URL')

    if static_url:
        return redirect(urljoin(static_url, filename))

    return app.send_static_file(filename)

无论您是在开发机器上还是在生产机器上,将 STATIC_URL 配置值设置为 CDN,静态文件请求将被重定向到那里。


重定向相对便宜,并且会被浏览器记住。如果你到了性能受到它们显着影响的地步,你可以在使用 CDN 时直接编写一个 links 的函数。

@app.template_global()
def static_url(filename):
    static_url = app.config.get('STATIC_URL')

    if static_url:
        return urljoin(static_url, filename)

    return url_for('static', filename=filename)

template_global 装饰器使该函数在所有模板中可用。当您需要静态文件的 url 时,请使用它而不是 url_for


可能已经有一个 Flask 扩展程序可以为您执行此操作。例如,Flask-S3 提供了一个 url_for 服务来自 AWS S3 的静态文件。

这个 flask cdn integration guide may be worth taking a read through. Basically you can install the Flask-CDN extension 并在你的 app.py 文件中定义你的 CDN URL 像这样:

from flask import Flask
from flask.ext.cdn import CDN

app = Flask(__name__)
app.config['CDN_DOMAIN'] = 'cdn.yourdomain.com'
CDN(app)

我在使用 Flask Assets 和 Flask-CDN 时遇到了类似的问题。我发现 Flask-CDN 尝试为每个资产生成时间戳,但未能成功。失败后它将恢复为相对 URL。

添加 app.config['CDN_TIMESTAMP'] = False 解决了问题。