Flask默认不给静态文件设强缓存,因为send_static_file不写Cache-Control头且动态生成ETag和Last-Modified,导致浏览器只能发条件请求;需禁用默认静态路由、自定义路由并手动设置Cache-Control头实现强缓存。

为什么 Flask 默认不给静态文件设强缓存
因为 send_static_file 默认不写 Cache-Control 头,且会动态生成 ETag 和 Last-Modified —— 这导致浏览器每次都要发条件请求(304 Not Modified),根本跳不过网络。强缓存要的是“别问服务器,直接用本地副本”,而默认行为恰恰相反。
接管静态路由并手动加 Cache-Control 头
最轻量、最可控的方式是禁用默认静态处理,自己写路由:
-
static_folder=None必须加,否则你的@app.route('/static/<path:filename>')会被 Flask 内置路由抢在前面匹配 - 用
send_from_directory('static', filename)安全读取文件(防路径遍历) - 对图片等长期不变资源,设
Cache-Control: public, max-age=31536000, immutable -
immutable很关键:它让浏览器连 F5 刷新都不发If-None-Match请求;旧版 Safari 会忽略它,但只回退到max-age行为,不影响正确性
from flask import Flask, make_response, send_from_directory
<p>app = Flask(<strong>name</strong>, static_folder=None)</p><p>@app.route('/static/<path:filename>')
def static(filename):
response = make_response(send_from_directory('static', filename))
if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.webp', '.gif')):
response.headers['Cache-Control'] = 'public, max-age=31536000, immutable'
response.headers.pop('ETag', None)
return response按文件名哈希自动启用长效缓存
如果你用构建工具(如 Webpack/Vite)生成带哈希的文件名(如 logo.a1b2c3.png),可以更稳妥地启用强缓存:
立即学习“Python免费学习笔记(深入)”;
- 判断逻辑要落在文件名本身,而不是扩展名:检查
'.'是否在最后一段中多次出现(如main.abc123.js) - 避免对
favicon.ico、manifest.json等非哈希资源误加immutable - 配合构建时重命名或
url_for插件(如Flask-Static-Digest)才能真正实现缓存失效
生产环境别只靠 Flask 做缓存
Flask 自定义路由适合开发或小流量场景;生产中应把静态资源交给 Nginx 或 CDN:
- Nginx 可统一配置
location ~* \.(png|jpg|webp)$ { expires 1y; add_header Cache-Control "public, immutable"; } - CDN 能自动压缩、边缘缓存、支持
stale-while-revalidate等高级策略 - Flask 层缓存头只是兜底——一旦你忘了在 Nginx 配置,或 CDN 没生效,用户就掉回协商缓存
最易被忽略的一点:修改缓存策略后,老用户浏览器里已有旧响应头,不会自动更新;必须靠 URL 版本化(/static/logo.png?v=2.1)或文件名哈希来强制刷新缓存。


















