页面级缓存该用@cache.cached,因其默认基于request.path和query_string生成缓存键,适配HTTP请求上下文;@cache.memoize仅依据函数参数缓存,不感知URL、headers等,易导致多用户或不同参数请求命中同一缓存,造成内容错乱。

页面级缓存该用 @cache.cached 还是 @cache.memoize?
@cache.cached 是页面级缓存的正确选择,@cache.memoize 用于函数级结果缓存(比如数据库查询),它不感知 HTTP 请求上下文,无法区分不同 URL 参数或用户请求。页面缓存必须基于请求路径、查询参数、甚至 headers(如 Accept-Language)生成唯一 key,@cache.cached 默认就做这件事。
常见错误是直接套用 @cache.memoize 装饰视图函数,结果所有用户看到同一份缓存内容,或者带参数的 GET 请求(如 /user?id=123 和 /user?id=456)命中同一个缓存项——因为 memoize 只看函数参数,而 Flask 视图函数通常不显式接收 query string 参数。
-
@cache.cached(timeout=300)会自动提取request.path + request.query_string作为 key 基础 - 若需按用户身份缓存(如登录态不同显示不同内容),得手动加
key_prefix,例如key_prefix=lambda: f"user_{session.get('user_id') or 'anon'}" - 避免在 POST/PUT 视图上误用
@cache.cached——它默认对所有 HTTP 方法生效,但页面缓存只应作用于安全的 GET/HEAD 请求
如何让缓存键包含请求头(比如 Accept 或 User-Agent)?
默认缓存 key 不包含 headers,所以返回 JSON 的 Accept: application/json 和返回 HTML 的同一路由会共用缓存,导致格式错乱。解决方法是扩展 make_cache_key 函数,或使用 unless + 自定义 key 逻辑。
更稳妥的做法是重写 key_prefix,把它变成一个 callable,并在其中拼接关键 header:
立即学习“Python免费学习笔记(深入)”;
@app.route('/api/data')
@cache.cached(
timeout=60,
key_prefix=lambda: f"api_data_{request.headers.get('Accept', '').replace('/', '_')}_{hash(request.args.to_dict())}"
)
def api_data():
return jsonify({'data': get_expensive_result()})
- 注意:不要无差别包含所有 headers,
X-Forwarded-For、Cookie等动态值会导致 key 爆炸、缓存失效 -
hash(request.args.to_dict())比直接用str(request.args)更稳定(避免排序差异) - 如果用了 Nginx 或 CDN,确认它没擅自改写或剥离关键 headers,否则 Flask 拿不到真实值
缓存失效怎么触发?手动清除指定页面缓存有哪些方式?
Flask-Caching 本身不提供“按 URL 失效”接口,它的 cache.delete() 需要精确知道缓存 key。而 @cache.cached 生成的 key 是内部拼接的,直接猜容易出错。
推荐做法是在装饰器中显式指定可预测的 key_prefix,这样清除时就能反向构造 key:
@app.route('/blog/<int:post_id>')
@cache.cached(key_prefix='blog_post_')
def show_post(post_id):
return render_template('post.html', post=get_post(post_id))
<h1>失效时:</h1><p>cache.delete('blog<em>post</em>' + str(post_id))
- 不要依赖默认 key(如
view//blog/123),它可能随 Flask 版本或配置变化 - 涉及多个参数的场景(如分页 + 排序),把参数组合进
key_prefix字符串,例如f"list_page_{page}_{sort}" - 全局清空用
cache.clear(),但生产环境慎用——它会清掉所有缓存,包括非页面类数据(如@cache.memoize结果)
为什么本地开发用 SimpleCache 总是不生效?
SimpleCache 是内存型后端,每个 worker 进程独享一份缓存,Flask 开发服务器默认多进程(threaded=False)时,各请求落在不同进程,彼此看不到对方的缓存。现象是:刷新一次有缓存,再刷新又重新计算。
- 开发时设
threaded=True(默认已开启)+processes=1,确保单进程运行 - 或换用
RedisCache/FileSystemCache,它们跨进程共享 - 验证是否生效:在视图里加
print("CALCULATING..."),连续刷新两次没输出,说明缓存命中 - 别在生产用
SimpleCache,它不支持过期、不支持并发清理,只适合 demo 或单元测试
页面级缓存真正难的不是配置,而是判断哪些页面值得缓存、哪些请求头该纳入 key、以及失效时机是否和业务更新节奏对齐——比如一篇博客修改后,不仅要删自己那条缓存,还可能要连带清掉相关列表页。这些没法靠插件自动完成。


















