在 Nuxt.js 中利用缓存
在 Nuxt.js 中利用缓存
在 Nuxt.js 中利用缓存
我第一次接触缓存这个话题是在用 Vue.js 实现电视机顶盒软件的时候。Evan You,我想在创建 Vue.js 库的时候,肯定没想到电视软件会用到前端 JavaScript 框架 :D 。好了,回到正题。那时候,大家都在讨论缓存。“缓存这个,缓存那个,但一定要缓存,因为里面包含敏感数据”。从那时起,我一直在研究各种缓存实现,所以现在我决定深入探讨一下这个话题,并以一种简洁有趣的方式呈现给大家。
实施缓存策略和策略可以帮助提升网站性能。如果您对此主题感兴趣,可以查看我的其他文章:
如果你已经了解缓存的概念,你可以转到Nuxt 部分
什么是 Web 缓存?
正如维基百科所述:
A Web cache (or HTTP cache) is a system for optimizing the World Wide Web. It is implemented both client-side and server-side. The caching of images and other files can result in less overall delay when browsing the Web.
换句话说,缓存是一种用于减少查看页面所需时间的系统(加载所有必要的静态资产、内容请求等)。
我们可以定义两种主要类型的缓存;forward
和reverse
。
- 转发- 转发缓存是指位于 Web 服务器网络之外的缓存,例如客户端的 Web 浏览器中的缓存。网络感知转发缓存仅缓存访问量较大的项目。位于客户端和 Web 服务器之间的代理服务器可以评估 HTTP 标头并选择是否存储 Web 内容。
- 反向- 位于一台或多台 Web 服务器的前端,加速来自互联网的请求并降低服务器峰值负载。这通常是一个内容分发网络 (CDN),它会在整个网络的各个节点保留 Web 内容的副本。
CDN 允许快速传输加载互联网内容所需的资产,包括 HTML 页面、javascript 文件、样式表、图像和视频。
缓存如何工作?
想象一下以下请求以方法的形式从前端发送到后端。
getDataFromDatabase()
-> 花费 X 毫秒来获取数据并将其返回到前端。
如果有多个用户使用您的网站(相信我,确实有),您的服务器很可能会在一定数量的请求之后无法将数据传递给用户。
那么,如果我们能以某种方式将响应存储在另一个工具中,这样就不用一遍又一遍地运行相同的方法并向数据库请求数据,而是直接返回前一个请求的结果,那会怎么样呢?这不是很棒吗?
我们来看看下面的伪代码:
if request in cache {
return cache[request] // This is called a cache hit
} else {
req = getDataFromDatabase() //
cache[request] = req // This is called a cache miss
return req //
}
这就是缓存的实际工作原理。如果某个请求在缓存中,它将从缓存中返回响应,而不是从服务器(和数据库)请求数据。
什么时候使用缓存?
缓存是一种强大的机制,可以大大提高我们页面的性能,但应谨慎使用。
如果出现以下情况,我们应该使用缓存:
- 我们的请求计算相当慢
- 计算将连续运行多次
- 当特定输入的输出相同时
- 托管提供数据库访问费用。
*记住不要对特定用户的请求/路由/资源使用缓存。如果对 IE/get-user-data
端点使用缓存,最终可能会向不同的用户提供不同的用户数据。哎哟!
缓存类型
我们可以定义三种主要的缓存类型:browser
、server
和proxy
。
服务器
在这种情况下,缓存机制以应用程序、工具或软件的形式位于服务器上。常见的服务器缓存软件类型包括:
浏览器
在这种情况下,缓存机制位于浏览器中,主要用于缓存图像、样式、资产等资源。
代理人
在这种情况下,缓存机制位于代理服务器或反向代理服务器中,如Nginx、Apache或Varnish,并且很可能是 ISP(互联网服务提供商)的一部分。
使用缓存的好处
缓存是一种强大的机制,如果使用得当,可以大大提高我们网站的性能:
- 减少延迟
- 减少服务器带宽
- 减少服务器负载
HTTP 标头
服务器的每个响应都会返回数据和特定的标头。这些标头会指示浏览器如何处理缓存,以便将某些请求存储在浏览器缓存中。为了更好地理解它们的工作原理,我们应该关注两个主要的缓存标头expires
:cache-control
过期
Expires HTTP 标头包含响应被视为过期的日期/时间。
无效到期日期值为 0,表示过去的日期,意味着资源已经过期。
注意:如果响应中存在带有 max-age 或 s-maxage 指令的 Cache-Control 标头,则会忽略 Expires 标头。
Expires: Wed, 21 Oct 2015 07:28:00 GMT
缓存控制
Cache-Control HTTP 标头包含请求和响应中用于缓存的指令(说明)。如果某个指令存在于请求中,并不意味着该指令也存在于响应中。
Private
- 仅缓存在客户端Public
- 也可以缓存在代理中no-store
- 内容不会被缓存no-cache
- 内容可以缓存,但需要服务器验证max-age
- 告诉浏览器保留缓存一定秒数
欲了解更多指令,请访问开发者 Mozilla。
缓存验证
为了检查验证,服务器可能会在响应中发送一个或多个验证标头,客户端使用这些验证标头向服务器发出条件请求。
为此使用了两个元素;Etag
和'':
ETag
它是实体标签的缩写,是服务器发送的与资源关联的唯一标识符。客户端使用该 ETag 向服务器发送请求,以检查内容是否已更改。
Cache-Control: max-age=600 Public
ETag: "123dadwad3211wda"
客户端将继续使用缓存中的这张图片 600 秒。此后,客户端将使用If-None-Match
标头向服务器发出请求,服务器会将之前提到的 ETag 作为值发送。然后,服务器会将新的内容添加到 ETag 中。如果两者不匹配,服务器将返回新的 ETag 和新的资源,用于替换当前图片。
如果它与现有图像匹配,服务器将响应状态代码,304 Not Modified
并且客户端将再更新缓存 600 秒。
ETag 有两种类型:
- 强——
ETag: "123dadwad3211wda"
两种资源完全相同。 - 弱
ETag: W/"123dadwad3211wda"
——两种资源可以被认为是相同的。
上次修改时间
指示内容最后修改的日期和时间。当内容过期时,服务器将使用 If-Modified-Since 标头发出带有最后修改日期的条件请求,然后服务器将使用该请求返回304 Not Modified
或返回新的响应。
服务器
Last-Modified: Mon, 24 Mar 2021 11:15:30 GMT
客户
If-Modified-Since: Mon, 24 Mar 2021 11:15:30 GMT
问答
问:如果响应中同时存在两个标头会怎样?
答:参数 ETag 和 If-None-Match 以及 Last-Modified 和 If-Modified-Since 都被发送,服务器会检查这两个值以返回 304 Not Modified 或返回新内容。
问:如果响应中没有验证标头会怎样?
答:不会调用任何验证和刷新现有缓存的函数。一旦内容过期,就会立即请求新的内容。
缓存策略
由于它受许多因素的影响,因此没有统一的答案,但通常我们可以定义两个主要的缓存类别:
- 轻量级缓存 - 即 HTML。它被缓存,但客户端在使用前需要与服务器进行验证。通过使用它,我们可以确保客户端始终获取最新的 HTML,只要服务器上有可用的 HTML 文件。但如果 HTML 文件尚未更新,客户端可以避免下载,而是直接使用浏览器中缓存的文件。
Cache-Control: Private, no-cache
- 积极缓存 - 例如 CSS、JavaScript、图像。通过以下示例,我们将这些文件长期缓存在公共缓存中。
Cache-Control: Public, max-age=23412213
Nuxt.js
您可以使用 Vue.js 提供并由 Nuxt 适配的内置保持活动缓存机制来缓存非活动组件实例而不销毁它们。
https://nuxtjs.org/docs/features/nuxt-components/#keep-alive
浏览器缓存中间件
通过使用以下辅助函数作为 Nuxt 中间件,您可以Cache-Control
为页面设置标题并相应地缓存内容。
// helpers/cacheControl.js
const cacheControl = (values) => ({ res }) => {
if (!process.server) return;
const cacheControlValue = Object.entries(values)
.map(([key, value]) => `${key}=${value}`)
.join(',');
res.setHeader('Cache-Control', cacheControlValue);
};
export default cacheControl;
然后,在您的某个页面中将此帮助程序用作中间件,如下所示:
// Home.vue
export default {
name: 'Home',
middleware: cacheControl({
'max-age': 60,
'stale-when-revalidate': 5
}),
...
}
SSR缓存
用于 nuxt 服务端渲染的缓存中间件。它支持各种缓存提供程序,例如 Redis、memcached 等。
cache: {
useHostPrefix: false,
pages: [
'/page1',
'/page2',
],
store: {
type: 'memory',
max: 100,
ttl: 60,
},
},
基于 Redis 的缓存中间件:
- 便于使用
- 在 redis 中缓存整个页面
- 每个页面有单独的过期时间
- API请求缓存
并且有许多配置选项供您尝试。
[
'nuxt-perfect-cache',
{
disable: false,
appendHost: true,
ignoreConnectionErrors:false, //it's better to be true in production
prefix: 'r-',
url: 'redis://127.0.0.1:6379',
getCacheData(route, context) {
if (route !== '/') {
return false
}
return {
key: 'my-home-page',
expire: 60 * 60
} // 1 hour
}
}
]
组件缓存
用于组件级缓存的 Nuxt.js 包装器
{
modules: [
// Simple usage
'@nuxtjs/component-cache',
// With options
['@nuxtjs/component-cache', { maxAge: 1000 * 60 * 60 }],
]
}
概括
做得好!现在,你应该更加了解缓存的概念以及如何充分利用它的潜力了。
奖励链接
- https://www.youtube.com/watch?v=n__c7xY1ZcI
- https://www.youtube.com/watch?v=HiBDZgTNpXY
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
- https://vueschool.io/articles/vuejs-tutorials/vue-js-performance-mastering-cache/
- https://medium.com/@oahehc/whats-the-best-way-to-set-the-cache-control-header-4fdae94da054