背景
SSR相对于静态页面是非常消耗服务器资源的,所以在网站访问量较大时通常会将前端页面进行缓存,在Next.js中我们需要渲染AJAX的内容需要在前端使用getServerSideProps进行动态内容的渲染。很多网页的数据变化不是很频繁通常不需要每次都发起请求和渲染,所以本文来讲解如何缓存Next.js渲染的SSR页面。如果有同学不清楚服务器缓存的原理可以看之前发布的Express使用服务端缓存。
Next.js内置的SSR本身不提供内置的缓存方案(有兴趣同学可以了解一下ISR),但是提供了一个自定义服务器方案,我们可以自己来设置启动和网站进入到返回渲染结果的流程。
安装插件
自定义缓存使用Express来做路由系统,使用lru-cache做缓存
代码语言:javascript复制npm i express lru-cache nodemon
//or
yarn add express lru-cache nodemon
编写
1.首先在根目录下创建一个server.js文件(命名不固定,别的也行)
2.代码:
代码语言:javascript复制const express = require('express');
const next = require('next');
const LRUCache = require('lru-cache');
const port = 5678; //端口
const isDev = process.env.NODE_ENV === 'development';
const app = next({
dev: isDev
});
// nextjs原生请求处理函数
const handle = app.getRequestHandler();
// 缓存工具初始化
const ssrCache = new LRUCache({
max: 100,
ttl: 1 * 60 * 60 * 1000, // 1小时缓存
});
//渲染和处理缓存
function renderAndCache(req, res) {
let pagePath = req.path;
let queryParams = req.query;
const key = req.url;
// 如果缓存中有直出的html数据,就直接将缓存内容响应给客户端
if (ssrCache.has(key)) {
res.send(ssrCache.get(key));
return
}
// 如果没有当前缓存,调用renderToHTML生成直出html
app.renderToHTML(req, res, pagePath, queryParams)
.then((html) => {
if (res.statusCode === 200) {
// 使用缓存工具将html存放
ssrCache.set(key, html);
} else {
ssrCache.delete(key);
}
// 响应直出内容
res.send(html);
})
.catch((err) => {
app.renderError(err, req, res, pagePath, queryParams)
})
}
async function main() {
await app.prepare(); //准备(初始化)
const server = express();
server.listen(port, (err) => {
if (err) throw err;
console.log(`>开始运行于: http://localhost:${port}`);
});
//对哪些页面进行缓存
server.get('/article/*', (req, res) => renderAndCache(req, res));
server.get('*', (req, res) => handle(req, res));
}
main()
讲解
主要流程也十分简单,使用缓存插件并且配置好,在每次被访问时判断缓存中是否存在,如果存在就返回缓存中的内容,如果不存在,就返回实时渲染的内容,并且缓存起来。
我在项目中使用,基本就是这个样子,我在项目中只对/article/*路径进行了缓存。对于_next路径的静态文件或者public下的图片不要和缓存路由重合。需要使用handle函数进行渲染(handle函数是Next.js内置的服务器渲染函数)。
例:
代码语言:javascript复制server.get('/robots.txt', (req, res) => handle(req, res));
package.json配置
代码语言:javascript复制 "scripts": {
"dev": "cross-env NEXT_PUBLIC_ENV=development next dev -p 5678",
"dev:cache": "cross-env NEXT_PUBLIC_ENV=development nodemon server.js",
"build": "cross-env NEXT_PUBLIC_ENV=production next build",
"build:test": "cross-env NEXT_PUBLIC_ENV=development next build",
"start": "cross-env NEXT_PUBLIC_ENV=production nodemon server.js",
"start:no-cache": "cross-env NEXT_PUBLIC_ENV=production next start -p 5678",
"start:test": "cross-env NEXT_PUBLIC_ENV=development next start -p 5678",
"analyze": "cross-env ANALYZE=true next build",
"analyze:server": "cross-env BUNDLE_ANALYZE=server next build",
"analyze:browser": "cross-env BUNDLE_ANALYZE=browser next build"
},
我在package中设置了很多命令,开发、打包、启动运行、统计。其中包括了测试环境的打包和运行,以及两个环境的统计。server.js中的代码我使用dev:cache来启动。需要注意的是我设置环境变量使用的是NEXT_PUBLIC_ENV而非NODE_ENV,server.js中是我为了迎合默认变量名而修改的,如果你复制package.json的代码记得修改一下,以便统一环境变量