如何缓存含getServerSideProps的Next.js动态渲染页面?
解决方案:基于用户状态的SSR页面缓存优化
针对你的需求,推荐结合Next.js 请求头自定义 + CDN 缓存规则的方案,既保留SSR的用户体验,又能让Cloudflare根据用户登录状态缓存不同渲染版本,无需修改路由或放弃SSR。
核心思路
通过中间件(Middleware)提前识别用户登录状态,为请求添加自定义标识头;再在getServerSideProps中根据这个标识获取状态,同时设置合理的缓存头和Vary字段,让CDN(Cloudflare)基于用户状态缓存对应的渲染结果。
步骤1:添加Middleware处理用户状态
在项目根目录创建middleware.ts,提前解析用户登录状态并添加自定义请求头:
import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; export function middleware(request: NextRequest) { // 从Cookie/请求上下文获取用户ID,逻辑和你现有getUserIdOrNull一致 const userId = getUserIdOrNullFromCookie(request.cookies); // 简化为两种状态:登录/未登录 const userStatus = userId ? "logged-in" : "anonymous"; // 给后续请求添加自定义标识头 const modifiedHeaders = new Headers(request.headers); modifiedHeaders.set("X-User-Status", userStatus); return NextResponse.next({ request: { headers: modifiedHeaders } }); } // 仅匹配需要缓存的/stuff页面 export const config = { matcher: "/stuff" };
步骤2:修改getServerSideProps设置缓存规则
更新pages/stuff.ts中的getServerSideProps,读取自定义头并设置CDN缓存策略:
export function getServerSideProps(context) { // 从自定义头获取用户状态 const userStatus = context.req.headers["x-user-status"] as string; const isLoggedIn = userStatus === "logged-in"; // 设置缓存规则:允许CDN缓存(public),缓存1小时,过期时返回旧内容并后台更新 context.res.setHeader( "Cache-Control", "public, s-maxage=3600, stale-while-revalidate=86400" ); // 告诉CDN根据自定义头区分缓存版本 context.res.setHeader("Vary", "X-User-Status"); return { props: { somethingComplicated: getSomethingComplicated(isLoggedIn) } }; } export default function Home({ somethingComplicated }) { return <div>{somethingComplicated}</div>; }
方案优势
- 保留SSR:页面在服务端渲染完成后再返回,用户体验好;
- CDN缓存有效:Cloudflare会根据
X-User-Status缓存两个版本(登录/未登录),命中率高; - 无需修改路由:用户访问的URL始终是
/stuff,没有复杂的重定向逻辑; - 性能兼顾:
stale-while-revalidate保证缓存过期时,用户仍能快速获取旧内容,后台异步更新缓存。
注意事项
- 确保Cloudflare支持缓存带
Vary头的响应(默认支持,若有异常可检查缓存规则); - 如果
getSomethingComplicated的结果随用户个体差异(而非仅登录状态)变化,可将X-User-Status替换为用户ID的哈希值,但需注意缓存键数量不要过多,避免缓存碎片化; - 若直接使用Cookie作为
Vary字段,需确保Cookie中仅包含必要的登录标识,避免因Cookie内容过多导致缓存键爆炸。
内容的提问来源于stack exchange,提问作者evandwight
相关产品推荐
相关产品推荐

