在 Next.js 中,BSR(Browser-Side Rendering)、SSR(Server-Side Rendering)和 SSG(Static Site Generation) 是三种常见的渲染方式,它们各有适用场景:
BSR 指的是在浏览器端动态获取数据并渲染页面。在 Next.js 中,这通常发生在 useEffect() 或客户端 API 请求中。
import { useEffect, useState } from 'react';
export default function Page() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(data => setData(data));
}, []);
return <div>{data ? data.message : '加载中...'}</div>;
}
SSR 指的是 在服务器端渲染 HTML 并返回给客户端。Next.js 使用 getServerSideProps()
来实现 SSR。
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return { props: { data } };
}
export default function Page({ data }) {
return <div>{data.message}</div>;
}
SSG 是 在构建时生成静态 HTML 文件,并在请求时直接返回该文件。Next.js 使用 getStaticProps()
进行 SSG。
export async function getStaticProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return { props: { data }, revalidate: 10 }; // 10 秒后自动重新生成
}
export default function Page({ data }) {
return <div>{data.message}</div>;
}
渲染方式 | 适用场景 | SEO 友好性 | 性能 | 数据获取时间 |
---|---|---|---|---|
BSR(客户端渲染) | 交互性强、个性化内容 | ❌ 差 | ⬆ 快(但可能影响 FCP) | 客户端请求后 |
SSR(服务器端渲染) | 需要最新数据、SEO 重要 | ✅ 好 | ⬇ 慢(依赖服务器) | 每次请求时 |
SSG(静态生成) | 静态内容、博客等 | ✅ 最佳 | ⬆⬆ 最高 | 构建时(可用 ISR 更新) |
如果页面的数据不会频繁更新,建议使用 SSG(静态生成)提高性能;如果需要每次请求最新数据,使用 SSR(服务器渲染);如果是个性化内容或用户特定数据,使用 BSR(客户端渲染)。
要判断你的 Next.js 页面正在使用 BSR、SSR 还是 SSG,你可以使用以下方法:
在 Next.js 中,不同的渲染模式使用不同的方法:
渲染模式 | 关键方法 |
---|---|
BSR(客户端渲染) | 只使用 useEffect() 或 API 请求,无 getStaticProps() / getServerSideProps() |
SSR(服务器端渲染) | 使用 getServerSideProps() |
SSG(静态站点生成) | 使用 getStaticProps() |
你可以打开 pages/
目录下的文件,检查是否有 getStaticProps()
或 getServerSideProps()
方法:
// 如果有 getStaticProps(),说明是 SSG
export async function getStaticProps() {}
// 如果有 getServerSideProps(),说明是 SSR
export async function getServerSideProps() {}
// 只有 useEffect() 而没有上面两个方法,说明是 BSR(客户端渲染)
Next.js
开发环境的 console.log()
检查在 getServerSideProps()
或 getStaticProps()
里加 console.log()
,然后在服务器终端(不是浏览器控制台)查看是否打印:
export async function getServerSideProps() {
console.log('SSR 渲染发生了!');
return { props: { time: new Date().toISOString() } };
}
console.log()
代码在 useEffect()
里运行,说明是 BSR。页面请求方式
document
类型的请求(通常是 localhost:3000
或你的页面 URL)。SSR
x-nextjs-page
,并且 cache-control
可能是 no-cache
(意味着服务器每次都重新生成)。x-nextjs-page: /my-page
cache-control: no-store, no-cache, must-revalidate
SSG
cache-control
可能是 public, max-age=...
,表示该页面是静态的,可以缓存。cache-control: public, max-age=3600, stale-while-revalidate=59
BSR
fetch('/api/...')
)。document
请求时,返回的 HTML 可能是一个基本结构,数据是客户端动态填充的。HTML 源码
Ctrl + U
)。示例:
<!-- 服务器渲染 (SSR 或 SSG) -->
<div id="content">Hello, SSR!</div>
<!-- 客户端渲染 (BSR) -->
<div id="content"></div>
<script>
document.getElementById('content').innerHTML = 'Hello, BSR!';
</script>
next build && next start
观察如果你在 next dev
(开发模式)下不确定,可以运行:
next build && next start
然后:
console.log()
判断是否有服务器端执行判断方法 | BSR(客户端渲染) | SSR(服务器端渲染) | SSG(静态站点生成) |
---|---|---|---|
代码检查 | useEffect() 进行数据请求 |
getServerSideProps() |
getStaticProps() |
终端日志 | 只在浏览器执行 console.log() |
服务器每次请求都会有 console.log() |
服务器 构建时 执行 console.log() |
网络请求 | 额外的 fetch() 请求 |
document 请求有 cache-control: no-cache |
document 请求有 cache-control: public, max-age=... |
查看 HTML 源码 | 初始内容为空,JS 填充 | HTML 直接包含完整数据 | HTML 直接包含完整数据 |
运行 next build && next start |
不影响 | 每次请求都会重新执行 | 只在构建时执行 |
如果你不确定,建议:
getServerSideProps()
/ getStaticProps()
。console.log()
观察是否在服务器端运行。这样你就能判断你的 Next.js 应用使用的是什么渲染模式了!
const handleSaveName = async () => {
try {
setEditing(true)
await updateUserProfile({ url: 'account/name', body: { name: editName } })
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
mutateUserProfile()
setEditNameModalVisible(false)
setEditing(false)
}
catch (e) {
notify({ type: 'error', message: (e as Error).message })
setEditNameModalVisible(false)
setEditing(false)
}
}
你的 handleSaveName
方法是 客户端渲染(BSR,Browser-Side Rendering),它不涉及 getServerSideProps()
或 getStaticProps()
,而是通过 前端 JavaScript 进行 API 调用并更新 UI。
没有 getServerSideProps()
或 getStaticProps()
:
React
组件内部的一个 async
方法,而不是 Next.js 提供的 getServerSideProps()
或 getStaticProps()
。使用了 await updateUserProfile(...)
:
updateUserProfile
发送 API 请求(可能是 fetch()
或 axios
),这是典型的 客户端数据获取(Client-side Fetching)。handleSaveName
后才请求。mutateUserProfile()
:
SWR
或 react-query
之类的状态管理库,用于在客户端重新拉取数据,属于 BSR 逻辑。setEditing(true)
、setEditNameModalVisible(false)
:
useState()
),只在浏览器中运行,不涉及服务器端渲染。handleSaveName
方法属于 BSR(客户端渲染),因为:useState()
和前端 notify()
来管理 UI 状态。getServerSideProps()
或 getStaticProps()
,不会在页面加载时提前渲染数据。如果你想让数据请求在 服务器端渲染(SSR) 时执行,而不是在客户端触发,你需要:
把数据获取逻辑放到 getServerSideProps()
里:
export async function getServerSideProps(context) {
const res = await fetch('https://your-api.com/account/name')
const data = await res.json()
return {
props: { name: data.name },
}
}
name
在服务器端就会预先加载,页面渲染时已经有数据了。但你的 handleSaveName
是 用户交互触发的操作,一般不会用 SSR,因为 SSR 适合 初始加载,而 handleSaveName
适合 用户操作后的更新,所以 BSR 是合理的选择!