Django REST Framework缓存分页视图返回两种不同响应的问题
Django REST Framework分页视图缓存重复请求返回不同响应问题
问题描述
使用带有2小时缓存的DRF分页列表视图时,重复请求同一端点有时返回不同大小的响应。已排除缓存过期、数据变更、region参数不一致的可能,怀疑存在多个缓存响应但不清楚具体机制。
视图代码
class MyListView(generics.ListAPIView): model = MyListModel serializer_class = MyListSerializer pagination_class = PageNumberPagination pagination_class.page_size = 1000 def get_queryset(self): region = self.kwargs.get('region') sort_param = '-date_created' return MyListModel.objects.filter(region=region).order_by(sort_param) @method_decorator(cache_page(2*60*60)) def get(self, *args, **kwargs): return super().get(*args, **kwargs)
缓存清理代码(每日cronjob执行)
from django.core.cache import cache cache.clear()
问题原因及解决方案
1. 缓存键受请求头干扰
cache_page默认会根据完整请求信息生成缓存键,包括Accept-Encoding(如gzip压缩标识)、User-Agent等请求头。不同客户端发送的请求头差异会导致生成不同缓存键,进而存储多个响应。
解决方法:自定义缓存键生成函数,只保留关键参数
def custom_cache_key(request, *args, **kwargs): # 仅保留请求路径、region参数和分页参数作为缓存键依据 key_parts = [ request.path, request.GET.get('page', '1'), request.resolver_match.kwargs.get('region', '') ] return ':'.join(key_parts) class MyListView(generics.ListAPIView): # 其他代码不变 @method_decorator(cache_page(2*60*60, key_func=custom_cache_key)) def get(self, *args, **kwargs): return super().get(*args, **kwargs)
2. 分页参数的隐性差异
即使未显式传递page参数,部分客户端或中间件可能会自动添加隐性分页参数,导致缓存键不一致。自定义缓存键时需强制统一分页默认值(如默认page=1)。
3. 分布式缓存的一致性问题
如果使用Redis集群等分布式缓存,需确认缓存键的哈希路由规则,避免同一请求被路由到不同节点存储不同响应。同时检查缓存是否开启分片、多副本等可能导致数据不一致的配置。
4. 验证缓存键的实际生成值
临时在视图中打印缓存键,确认同一请求是否生成相同键:
from django.utils.cache import get_cache_key class MyListView(generics.ListAPIView): # 其他代码不变 def get(self, *args, **kwargs): key = get_cache_key(self.request) print(f"当前缓存键: {key}") return super().get(*args, **kwargs)
内容的提问来源于stack exchange,提问作者stackunderflow
相关产品推荐
相关产品推荐

