Django类视图配置Cache-Control与ETag,实现城市ID动态缓存校验
解决方案
问题出在你的Cache-Control配置上:原来的max-age=3600会让浏览器在1小时内直接使用本地缓存,完全不向服务器发送请求,自然不会带上If-None-Match头,只有硬刷新才会强制触发校验。要实现每次请求都自动校验城市ID,需要调整缓存策略,同时完善ETag的生成逻辑:
1. 调整缓存控制头
把Cache-Control改为private, no-cache,这个指令的意思是:浏览器可以缓存响应,但每次使用缓存前必须向服务器校验ETag是否匹配,这样就能保证每次请求都会触发服务器的ETag校验逻辑。
2. 修正ETag生成逻辑
你的calculate_etag_value函数里的city_id没有明确来源,必须从当前请求中获取(比如请求参数、URL路径参数),否则无法正确生成对应城市的ETag。
修改后的完整代码
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status def calculate_etag_value(request): # 从请求中获取城市ID,示例为从query参数获取,根据你的实际场景调整 city_id = request.query_params.get('city_id', '') # 给ETag加前缀避免冲突,同时符合HTTP规范用双引号包裹 return f'"city-{city_id}"' class MyAPIView(APIView): def get(self, request): current_etag = calculate_etag_value(request) # 处理客户端传来的ETag,去掉可能的双引号再对比 client_etag = request.META.get('HTTP_IF_NONE_MATCH', '').strip('"') current_etag_clean = current_etag.strip('"') if client_etag == current_etag_clean: return Response(status=status.HTTP_304_NOT_MODIFIED) # 获取对应城市的最新数据 city_id = request.query_params.get('city_id') if not city_id: return Response({"error": "城市ID不能为空"}, status=status.HTTP_400_BAD_REQUEST) my_data = retrieve_data(city_id) # 传入城市ID获取对应数据 headers = { 'Cache-Control': 'private, no-cache', # 关键修改:强制每次校验 'ETag': current_etag, } response_data = { "message": "API info found", "data": my_data, } return Response(response_data, status=status.HTTP_200_OK, headers=headers)
关键说明
no-cache不是禁止缓存,而是强制缓存校验:浏览器会保存缓存,但每次请求都会把ETag发给服务器确认,匹配则返回304复用缓存,不匹配则返回新数据。- ETag格式建议用双引号包裹(符合HTTP标准),所以对比前要去掉客户端传来的引号。
- 确保
retrieve_data函数能根据城市ID返回对应的数据,保证ETag和数据的一一对应。
内容的提问来源于stack exchange,提问作者Mayank
相关产品推荐
相关产品推荐

