Next.js的SSR
在 Next.js 中,服务器端渲染(Server-Side Rendering,SSR)是一项核心特性,它允许在服务器端生成 HTML 内容,然后将其发送到客户端
1. 常用的客户端渲染(CSR)
传统的客户端渲染(CSR)应用在初始加载时,浏览器先加载一个空白的 HTML 页面,然后下载 JavaScript 文件,在客户端执行这些脚本后才渲染出页面内容。
2. 服务端渲染(SSR)
服务器端渲染是在服务器端就把页面的 HTML 内容生成好,直接发送给浏览器,浏览器可以立即显示页面内容。
3. 服务端渲染的优点
- 更好的 SEO:搜索引擎爬虫可以直接读取服务器端生成的 HTML 内容,有利于提高网站在搜索引擎中的排名。
- 更快的初始加载速度:用户可以更快地看到页面内容,减少白屏时间,提升用户体验。
- 兼容性好:即使浏览器不支持 JavaScript,也能正常显示页面内容。
4. 使用getServerSideProps
实现SSR
getServerSideProps是一个异步函数,它会在每次请求页面时在服务器端执行。在这个函数中,我们可以进行数据获取操作,然后将获取到的数据作为props返回给页面组件。
// pages/index.js
import React from 'react';const HomePage = ({ data }) => {return (<div><h1>Server-Side Rendered Page</h1><p>{data}</p></div>);
};export async function getServerSideProps() {// 模拟从API获取数据const res = await fetch('https://api.example.com/data');const data = await res.text();return {props: {data}};
}export default HomePage;
5. SSR的工作流程
- 客户端请求页面
- 服务器执行
getServerSideProps
获取所需数据 - 服务端渲染页面
- 服务端发送HTML到客户端
- 客户端的Next.js 会将客户端的 JavaScript 代码与服务器端生成的 HTML 进行水合,使页面具有交互性。
6. 减少SSR开销的方法
为了优化性能和减少服务器负载,可以采用缓存机制和静态生成(SSG)这两种重要的技术手段
6.1 内存缓存
可以使用 Node.js 的全局变量或第三方库(如 lru-cache)来实现内存缓存
npm install lru-cache
// pages/index.js
import React from 'react';
import LRU from 'lru-cache';// 初始化 LRU 缓存,设置最大缓存项为 100
const cache = new LRU({ max: 100 });const HomePage = ({ data }) => {return (<div><h1>Server-Side Rendered Page with Cache</h1><p>{data}</p></div>);
};export async function getServerSideProps() {const cacheKey = 'exampleData';// 检查缓存中是否存在数据if (cache.has(cacheKey)) {const cachedData = cache.get(cacheKey);return {props: {data: cachedData}};}// 若缓存中不存在数据,则从 API 获取const res = await fetch('https://api.example.com/data');const data = await res.text();// 将获取到的数据存入缓存cache.set(cacheKey, data);return {props: {data}};
}export default HomePage;
6.2 使用HTTP协议缓存
可以通过设置响应头来利用浏览器和 CDN 的 HTTP 缓存。在
getServerSideProps
中可以设置 revalidate 属性来实现增量静态再生(ISR)
export async function getServerSideProps() {const res = await fetch('https://api.example.com/data');const data = await res.text();return {props: {data},revalidate: 60 // 每 60 秒重新验证一次页面};
}
6.3 静态生成(SSG)
静态生成是指在构建时生成 HTML 文件,而不是在每次请求时动态生成。这使得页面可以直接从 CDN 提供,从而实现更快的加载速度和更好的性能。
6.3.1 getStaticProps
当页面内容在构建时就可以确定,并且不需要在每次请求时更新时,使用
getStaticProps
。
// pages/index.js
import React from 'react';const HomePage = ({ data }) => {return (<div><h1>Static Generated Page</h1><p>{data}</p></div>);
};export async function getStaticProps() {const res = await fetch('https://api.example.com/data');const data = await res.text();return {props: {data},// 可选:设置页面的重新验证时间(以秒为单位)revalidate: 60 };
}export default HomePage;
6.3.2 getStaticPaths
当使用动态路由(如 [id].js)时,需要使用 getStaticPaths 来指定哪些路径需要在构建时生成静态页面。
// pages/posts/[id].js
import React from 'react';const PostPage = ({ post }) => {return (<div><h1>{post.title}</h1><p>{post.content}</p></div>);
};export async function getStaticPaths() {const res = await fetch('https://api.example.com/posts');const posts = await res.json();const paths = posts.map((post) => ({params: { id: post.id.toString() }}));return { paths, fallback: false };
}export async function getStaticProps(context) {const id = context.params.id;const res = await fetch(`https://api.example.com/posts/${id}`);const post = await res.json();return {props: {post}};
}export default PostPage;
getStaticPaths
函数返回一个包含所有需要生成静态页面的路径数组 paths。
fallback
属性用于指定当访问未在构建时生成的路径时的行为:当 fallback 设置为 false 时,果用户尝试访问未在构建时生成的路径,Next.js 会返回 404 页面;当 fallback 设置为 true 时,Next.js 会立即返回一个占位页面给用户,同时在后台异步生成该页面的静态内容。生成完成后,页面会自动更新为完整的内容,并且后续对该路径的访问将直接返回预先生成的静态页面。