【问题标题】:Django REST framework still respond with cached data even after having empty redis keys即使有空的 redis 键,Django REST 框架仍然会响应缓存数据
【发布时间】:2021-11-17 19:23:22
【问题描述】:

上下文:使用方法装饰器 cache_page 在 Django REST 框架 (DRF) 中通过 redis ModelViewSet API 视图缓存时遇到问题。

文档参考:https://www.django-rest-framework.org/api-guide/caching/

代码片段:https://hastebin.com/apoqeloyav.py

示例场景

这是当前行为(使用 Swagger UI 手动测试)

  1. 向 /products 端点发送 GET 请求 -> 这将请求我的 DRF 服务器并缓存视图

  2. 再次向 /products 端点发送 GET 请求 -> 这会将产品数据作为缓存数据响应(已在开发工具网络选项卡“从磁盘缓存提供服务”中验证)。这也意味着它没有访问我的 DRF 服务器来检索数据。

  3. 向 /products/{product_id} 端点发送 PATCH 请求 -> 这将更新详细信息然后使缓存无效(此时 Redis 缓存键为空)

  4. 再次向 /products 端点发送 GET 请求 -> 这仍会将产品数据作为缓存数据响应(已验证,因为执行步骤 3 的更新数据仍然不存在)。这也意味着它没有访问我的 DRF 服务器来检索数据。

这是我的预期行为(使用 Swagger UI 手动测试)

  1. 向 /products 端点发送 GET 请求 -> 这将请求我的 DRF 服务器并缓存视图
  2. 再次向 /products 端点发送 GET 请求 -> 这会将产品数据作为缓存数据响应(在开发工具网络选项卡“从磁盘缓存提供服务”中验证)。这也意味着它没有访问我的 DRF 服务器来检索数据。
  3. 向 /products/{product_id} 端点发送 PATCH 请求 -> 这将更新详细信息然后使缓存无效(此时 Redis 缓存键为空)
  4. 再次向 /products 端点发送 GET 请求 -> 这应该响应来自数据库的产品数据。这意味着它会访问我的 DRF 服务器以检索更新的数据。

如何获得预期的结果,以便如果 redis 缓存为空,它应该访问我的 DRF 服务器以检索最新数据并缓存后续调用,直到它再次失效?另外,我不确定这是一个问题,还是只是正常行为。

这是我迄今为止在从 redis 中使缓存数据无效时尝试的方法,但它们都不起作用并且仍然提供缓存数据

  1. 将缓存过期时间设置为 0
  2. 将缓存值设置为无
  3. 以编程方式删除所有键
  4. 通过 redis-cli 删除所有键
  5. 关闭 redis-server -> 但仍为 from disk cache 提供服务,并且没有访问我的 DRF API 端点

这是我正在使用的版本

  • djangorestframework==3.11.0
  • Django==3.0.8
  • redis==3.5.3
  • drf-yasg==1.17.1 -> 这是 Swagger UI 文档
  • django-redis==5.0.0

【问题讨论】:

    标签: caching django-rest-framework redis


    【解决方案1】:

    来自 4. 的请求甚至没有命中 redis 缓存,因为它返回了一个本地缓存(注意响应代码中的“From disk cache”)。

    您应该区分公共缓存(即所有用户使用的服务器缓存)和私有缓存(用户的浏览器缓存)。

    我认为,当使用cache_page 装饰器时,除了缓存请求之外,它还设置“缓存控制”响应标头以允许对请求进行私有缓存。浏览器使用这些标头在本地缓存请求,并返回本地缓存的响应,直到max-age 过期。

    为了防止这种行为,在服务器级别,您可以使用 @never_cache 装饰器,它设置 Cache-control 响应标头以防止本地缓存,或使用 @cache_control(public=True) 仅允许请求的公共缓存(这也调整相应的缓存控制响应标头)。

    更多关于Controlling cache

    【讨论】:

    • 感谢您的回答。我的目标是仅将其缓存在 redis(公共缓存)中。我尝试使用cache_control(public=True) 就像你对cache_page 所说的那样,但它似乎仍在本地缓存它,即使Cache-control: public 在它的标题中。你推荐什么方法?在这种情况下我需要使用低级缓存吗?
    • 您似乎需要隐式设置缓存控制标头@cache_control(public=True, max_age=0, no_cache=True, no_store=True, must_revalidate=True) 或使用设置所有这些值的@never_cache
    • 我尝试了你提到的两种方法,但是它没有在我的 redis 上存储任何缓存?并且经过检查,每个发送的请求都会为我提供新数据
    猜你喜欢
    • 2018-12-08
    • 2021-08-19
    • 2014-08-14
    • 1970-01-01
    • 2016-12-27
    • 2020-12-04
    • 2017-03-12
    • 2020-03-01
    • 2020-07-27
    相关资源
    最近更新 更多