flask 看不到 .js 文件的变化
flask does not see change in .js file
我对我使用的 .js
文件之一进行了更改,无论我做什么,flask 都坚持从内存缓存中获取文件的最新版本,而没有更改。
为了澄清,我有以下结构。一切都以 foo.html
开头
return render_template foo.html
foo.html
内部有一个表单调用带有一些数据的烧瓶然后 returns 第二个模板 bar.html
:
return render_template bar.html
第二个模板调用一些 .js
文件,放在 static
文件夹中,但它不会在代码更改时更新。
我提到上面的结构是因为如果 .js
文件放在 foo.html
而不是 bar.html
那么 Flask 会 拿起文件的新变化。但是在 bar.html
Flask 中完全忽略了它们。
这是怎么回事?
唯一有效的方法是在浏览器上单击 "disable cache" 并重新加载。
最终这是一个令人沮丧的浏览器缓存问题,可以通过强制浏览器执行 "hard refresh" 来解决,这将是 browser/OS 相关的击键,但通常这是可行的:
- Windows: Ctrl+F5
- Mac: Cmd+Shift+R
- Linux: Ctrl+Shift+R
还有其他文件名技巧可以用来避免这个问题(在 OP 的评论中提到)。这些在您无法控制浏览器行为的生产环境中尤为重要。
对于非静态 Flask 响应,您可以设置 cache_control.max_age
属性,如果响应被缓存,它应该告诉浏览器何时过期响应。例如,如果你有一个 returns JSON 数据的 Flask XHR 端点,你可以这样做:
@app.route('/_get_ajax_data/')
def get_ajax_data():
data = {"hello": "world"}
response = jsonify(data)
response.cache_control.max_age = 60 * 60 * 24 # 1 day (in seconds)
return response
您通常还可以在生产 Web 服务器配置中为特定资源类型设置默认值(例如 CSS/JS/HTML/JSON/etc)
编辑 4/1/2019(与愚人节无关)
- Mac / Safari 击键现在显示为:Cmd+Opt+R(通过评论,谢谢!)。
- 请参阅@MarredCheese 的新答案,以获得非常优雅的 "filename trick" 强制浏览器忽略更新文件的缓存副本。
如果您使用 Flask 提供静态资产(这通常是开发环境中的情况),那么您可能需要设置 SEND_FILE_MAX_AGE_DEFAULT
configuration value:
Default cache control max age to use with send_static_file()
(the default static file handler) and send_file()
, as datetime.timedelta
or as seconds. Override this value on a per-file basis using the get_send_file_max_age()
hook on Flask or Blueprint, respectively. Defaults to 43200 (12 hours).
解决这个问题就像更新 app.config
字典一样简单,如下所示:
app = Flask(__name__)
...
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
如果这样做,您的浏览器将不会缓存 Flask 提供的静态资产。
缓存通常很好,因此不建议完全消除它。使用 control + F5 或任何进行硬刷新显然不是可扩展的解决方案,因为您必须在每台计算机上的每个浏览器中执行此操作.
更好的办法是让浏览器在大部分时间缓存文件,但不是在文件更新后立即缓存。您可以通过附加时间来实现此目的源文件最后更新为它的路径参数 URL。为简单起见,您可以对静态文件夹(或任何子文件夹)中的任何文件使用最近的修改时间,而不是单独查看每个文件。
Python
def dir_last_updated(folder):
return str(max(os.path.getmtime(os.path.join(root_path, f))
for root_path, dirs, files in os.walk(folder)
for f in files))
@app.route('/my-site')
def my_site():
return render_template('my-site.html',
last_updated=dir_last_updated('mydir/static'))
Jinja 模板
<script type="text/javascript" src="/static/my-script.js?u={{ last_updated }}"></script>
HTML 结果
<script type="text/javascript" src="/static/my-script.js?u=1547330602.31"></script>
使用 CTRL+ f5 刷新浏览器
使用:
if __name__ == '__main__':
app.config['TEMPLATES_AUTO_RELOAD'] = True
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
app.run(debug=True)
您可以使用 F5
或 CTRL + R
进行更新。
我对我使用的 .js
文件之一进行了更改,无论我做什么,flask 都坚持从内存缓存中获取文件的最新版本,而没有更改。
为了澄清,我有以下结构。一切都以 foo.html
return render_template foo.html
foo.html
内部有一个表单调用带有一些数据的烧瓶然后 returns 第二个模板 bar.html
:
return render_template bar.html
第二个模板调用一些 .js
文件,放在 static
文件夹中,但它不会在代码更改时更新。
我提到上面的结构是因为如果 .js
文件放在 foo.html
而不是 bar.html
那么 Flask 会 拿起文件的新变化。但是在 bar.html
Flask 中完全忽略了它们。
这是怎么回事?
唯一有效的方法是在浏览器上单击 "disable cache" 并重新加载。
最终这是一个令人沮丧的浏览器缓存问题,可以通过强制浏览器执行 "hard refresh" 来解决,这将是 browser/OS 相关的击键,但通常这是可行的:
- Windows: Ctrl+F5
- Mac: Cmd+Shift+R
- Linux: Ctrl+Shift+R
还有其他文件名技巧可以用来避免这个问题(在 OP 的评论中提到)。这些在您无法控制浏览器行为的生产环境中尤为重要。
对于非静态 Flask 响应,您可以设置 cache_control.max_age
属性,如果响应被缓存,它应该告诉浏览器何时过期响应。例如,如果你有一个 returns JSON 数据的 Flask XHR 端点,你可以这样做:
@app.route('/_get_ajax_data/')
def get_ajax_data():
data = {"hello": "world"}
response = jsonify(data)
response.cache_control.max_age = 60 * 60 * 24 # 1 day (in seconds)
return response
您通常还可以在生产 Web 服务器配置中为特定资源类型设置默认值(例如 CSS/JS/HTML/JSON/etc)
编辑 4/1/2019(与愚人节无关)
- Mac / Safari 击键现在显示为:Cmd+Opt+R(通过评论,谢谢!)。
- 请参阅@MarredCheese 的新答案,以获得非常优雅的 "filename trick" 强制浏览器忽略更新文件的缓存副本。
如果您使用 Flask 提供静态资产(这通常是开发环境中的情况),那么您可能需要设置 SEND_FILE_MAX_AGE_DEFAULT
configuration value:
Default cache control max age to use with
send_static_file()
(the default static file handler) andsend_file()
, asdatetime.timedelta
or as seconds. Override this value on a per-file basis using theget_send_file_max_age()
hook on Flask or Blueprint, respectively. Defaults to 43200 (12 hours).
解决这个问题就像更新 app.config
字典一样简单,如下所示:
app = Flask(__name__)
...
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
如果这样做,您的浏览器将不会缓存 Flask 提供的静态资产。
缓存通常很好,因此不建议完全消除它。使用 control + F5 或任何进行硬刷新显然不是可扩展的解决方案,因为您必须在每台计算机上的每个浏览器中执行此操作.
更好的办法是让浏览器在大部分时间缓存文件,但不是在文件更新后立即缓存。您可以通过附加时间来实现此目的源文件最后更新为它的路径参数 URL。为简单起见,您可以对静态文件夹(或任何子文件夹)中的任何文件使用最近的修改时间,而不是单独查看每个文件。
Python
def dir_last_updated(folder):
return str(max(os.path.getmtime(os.path.join(root_path, f))
for root_path, dirs, files in os.walk(folder)
for f in files))
@app.route('/my-site')
def my_site():
return render_template('my-site.html',
last_updated=dir_last_updated('mydir/static'))
Jinja 模板
<script type="text/javascript" src="/static/my-script.js?u={{ last_updated }}"></script>
HTML 结果
<script type="text/javascript" src="/static/my-script.js?u=1547330602.31"></script>
使用 CTRL+ f5 刷新浏览器
使用:
if __name__ == '__main__':
app.config['TEMPLATES_AUTO_RELOAD'] = True
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
app.run(debug=True)
您可以使用 F5
或 CTRL + R
进行更新。