6

我正在寻找一种模式,可以让我为我的用户改善 UX。我有一个在 CloudFront 后面运行的 REST 服务器,从前端的普通 React 应用程序中使用。

我将简化我的示例来说明我的问题。

我有一个名为GET /posts/<id>. 当浏览器请求它时,它带有一个max=age=180,这意味着它将存储在浏览器的缓存中,并且任何后续调用都GET /posts/<id>将在这 180 秒的持续时间内从浏览器的缓存中提供服务,之后它将再次访问 CDN 以尝试获取新副本。

这对大多数用户来说是可以的。我不介意任何帖子的更新在传播给所有用户之前延迟最多 3 分钟。但是有一个用户是这篇文章的作者。该用户可以使用PATCH /posts/<id>. 我们称该用户为 The Editor

这是我现在的一个场景:

  • 编辑器加载帖子页面,然后调用GET /posts/5
  • CDN 将最新的副本提供给前端。
  • 然后编辑器对帖子进行更改并将其提交到后端通过PATCH /posts/5.
  • 然后编辑器使用 Command-R(或 CTRL-R)刷新他的浏览器选项卡。
  • 结果,前端然后GET /posts/5再次请求 - 但从更改之前获取过时的副本,因为自上次以来还没有过去 180 秒,GET并且GETPATCH

我想要的体验是:

  • 编辑器加载帖子页面,然后调用GET /posts/5
  • CDN 将最新的副本提供给前端。
  • 然后编辑器对帖子进行更改并将其提交到后端通过PATCH /posts/5.
  • 在 Command-R 浏览器选项卡刷新后,无论在 180 秒内获得新副本之前,都会立即GET /posts/5返回带有编辑器所做更改的数据副本。PATCHttl
  • 至于其他用户,他们可以等待最多 180 秒,然后帖子中的更改才会传播给他们,当GET /posts/5

我正在使用 Axios,但我不认为 SWR 和 React-Query 支持突变。据我了解,这将允许编辑器为他刚刚PATCH'ed在服务器上的对象声明一个突变,以便他进行的任何后续调用GET /posts/5都将从那里得到服务,直到可以从后端获得更新的版本。

我的问题是:

  • 带有“突变”的 SWR 可以通过GET /posts/5透明的方式为突变对象服务吗?
  • 突变会在硬浏览器标签刷新后幸存下来吗?或浏览器关闭,重新打开和后续/GET posts/5
  • 是否有另一种模式/最佳实践来解决这个问题?
4

2 回答 2

2

TL;DR:只需在请求的末尾附加一个无害的、乱码的查询字符串GET /posts/<id>?version=whatever


好问题。我必须承认我不知道这个问题的完整答案,但我想在前端开发人员中分享一种众所周知的技术。

该技术称为缓存清除。我不确定这是否是最佳做法,但我很确定它已被广泛使用,因为它很容易理解。

想法很简单。当您将更改的查询字符串添加到末尾时,您实际上更改了 URL,因此没有缓存命中,您回避了整个缓存问题。

因此,针对您的特定用例的解决方案的详细步骤如下所示:

  1. 通常你只会请求GET /posts/<id>所有用户
  2. 当用户登录时,无论何种算法都会生成一个哈希键。为简单起见,我们只使用递增整数并调用它version。您将其存储version在 localStorage 中,以便它可以通过页面刷新而存活。
  3. 现在您需要区分用户在查看自己的帖子或其他人的帖子时的场景。当男人在看他自己的时候,你总是用GET /posts/<id>?version=n
  4. 每当用户编辑他的帖子并点击保存按钮时,您就会versionnn+1
  5. 下次他去发布视图页面时,应用程序会请求GET /posts/<id>?version=n+1未缓存的内容,并会检索最新的内容。
  6. 最后一件事,确保您的服务器安全地忽略该?version=n查询字符串。

我确信这个问题还有其他解决方案。我不是服务器配置和 HTTP 标头方面的专家,所以我不会进入该主题,但一定有一些东西需要寻找。

作为纯前端解决方案,有Serivce Worker API供您考虑。该 API 的主要目的是使开发人员能够以编程方式控制缓存策略。

使用此 API,您可以保留当前的应用程序代码,只需安装一个服务工作者,然后您可以在后台使用相同的缓存破坏技术来获取新内容,或者在用户使用时删除缓存(使用Cache API)编辑,甚至伪造用户刚刚发送GET /posts/<id>的回复。PATCH /posts/<id>

于 2021-03-31T09:10:11.063 回答
0

根据您使用的 CDN,您可以在将更新发布到帖子时手动使缓存无效。例如, cloudfront允许您指定要在下一个请求中获取新鲜的路径。

对于流量很大但更新很少的网站,这很有效,而且实施起来也很简单。但是,对于拥有大量作者和经常更改内容的网站,您需要获得更多创意。

我过去使用的一种策略是使用一种称为对象版本控制的技术,在这种技术中,您无需使对象的缓存无效,您只需发布一个带有时间戳的版本即可。这也意味着您需要在前端加载时发布清单文件。清单包含页面需要加载的所有内容的最新时间戳,并且 TTL 比其余内容短得多。当您发布新版本的帖子时,您将更新清单中的时间戳,并且在下次页面加载时前端会拉取最新版本。

于 2021-04-02T14:21:30.397 回答