基于Accept-Encoding头实现Flask缓存双格式响应的方案问询
解决方案:基于请求头区分Flask-Caching缓存条目
要实现同时缓存原生JSON和GZIP压缩版响应,核心是让Flask-Caching根据请求头的accept-encoding状态生成不同的缓存键,具体步骤如下:
1. 自定义缓存键生成函数
Flask-Caching默认的缓存键只包含路由和参数,我们需要扩展它,把请求是否需要gzip压缩的标识加入缓存键:
from flask import request from flask_caching import Cache cache = Cache(config={ "CACHE_TYPE": "SimpleCache", # 替换为你实际使用的缓存类型 # 其他缓存配置... }) def custom_cache_key(): # 判断请求头是否包含gzip编码需求 accepts_gzip = 'gzip' in request.headers.get('accept-encoding', '').lower() # 基于默认逻辑生成基础键,再拼接gzip标识 base_key = cache._make_cache_key() return f"{base_key}:gzip={str(accepts_gzip).lower()}"
2. 实现响应压缩与缓存结合的逻辑
用装饰器把压缩逻辑和缓存绑定,确保两种格式的响应都被缓存:
import gzip from flask import jsonify, make_response def gzip_cache(timeout=300): def decorator(f): @cache.cached(timeout=timeout, key_prefix=custom_cache_key) def wrapped(*args, **kwargs): # 获取原始数据 raw_data = f(*args, **kwargs) if not isinstance(raw_data, (dict, list)): return raw_data # 非JSON响应直接返回 json_str = jsonify(raw_data).get_data(as_text=True) accepts_gzip = 'gzip' in request.headers.get('accept-encoding', '').lower() if accepts_gzip: # 压缩并构建响应 compressed_data = gzip.compress(json_str.encode('utf-8')) resp = make_response(compressed_data) resp.headers['Content-Encoding'] = 'gzip' resp.headers['Content-Type'] = 'application/json' resp.headers['Content-Length'] = len(compressed_data) return resp else: # 返回原生JSON return jsonify(raw_data) return wrapped return decorator
3. 在视图函数中使用
给需要缓存和压缩的视图加上自定义装饰器即可:
@app.route('/api/large-data') @gzip_cache(timeout=3600) def get_large_data(): # 生成大体积JSON数据的逻辑(例如返回1.41MB的内容) large_payload = generate_large_data() return large_payload
关键说明
- 自定义缓存键通过
custom_cache_key函数,将gzip=True/False拼接在基础键后,不同请求头会生成完全独立的缓存条目,实现双缓存效果。 - 压缩操作仅在缓存未命中时执行一次,后续直接返回缓存好的压缩/原生响应,正好能节省你提到的31ms压缩耗时。
- 完全适配你使用的
flask==2.2.2和Flask-Caching==2.0.2版本,无需额外依赖。
内容的提问来源于stack exchange,提问作者Fabio
相关产品推荐
相关产品推荐

