求助:Next.js 13+Supabase实现SSG失败,始终触发SSR
Next.js 13 + Supabase 静态站点生成(SSG)问题排查与解决
你当前的核心问题是混淆了Next.js 13 App Router与Pages Router的静态生成机制,同时部分请求配置存在疏漏,导致页面始终以SSR方式渲染。以下是对尝试方法的问题分析及正确实现方案:
已尝试方法的问题点
方法1:通过API路由中转请求
- 页面组件中请求本地API时,未显式配置缓存策略,默认会被视为动态请求触发SSR
- 无需额外通过API路由中转,直接在页面组件请求Supabase更高效
方法2:带force-cache的fetch请求
- Supabase REST API默认响应头可能包含
Cache-Control: no-cache,会覆盖你的fetch缓存配置 - 未明确设置缓存有效期,无法确保构建时预渲染数据
- Supabase REST API默认响应头可能包含
方法3:使用getStaticProps
getStaticProps是Pages Router专属API,在App Router(app目录)中完全不生效
正确实现方案(App Router)
方案1:直接配置可缓存的Supabase REST请求
在页面组件中直接请求Supabase,强制缓存并覆盖默认缓存头:
// app/composers/page.tsx type Composer = { id: number; name: string; // 补充你的字段定义 }; async function getComposers() { const res = await fetch( `${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest/v1/composers?select=*&order=id.asc`, { cache: "force-cache", // 构建时预拉取数据并缓存 next: { revalidate: 86400 }, // 可选:设置每日重新验证,实现增量静态再生(ISR) headers: { "Apikey": process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, "Cache-Control": "s-maxage=86400, stale-while-revalidate" // 覆盖Supabase默认缓存头 } as HeadersInit, } ); if (!res.ok) throw new Error('获取作曲家数据失败'); const data: Composer[] = await res.json(); return data; } export default async function ComposersPage() { const composers = await getComposers(); return ( <div> <h1>作曲家列表</h1> <ul> {composers.map(composer => ( <li key={composer.id}>{composer.name}</li> ))} </ul> </div> ); }
方案2:使用Supabase客户端并配置缓存
如果使用Supabase JS客户端,需手动设置缓存头确保静态生成:
// app/composers/page.tsx import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'; type Composer = { id: number; name: string; }; async function getComposers() { const supabase = createClientComponentClient(); const { data, error } = await supabase .from('composers') .select('*') .order('id', { ascending: true }) .setHeader('Cache-Control', 's-maxage=86400, stale-while-revalidate'); if (error) throw error; return data as Composer[]; } // 注意:页面中不要使用cookies()、headers()等动态函数,否则会触发SSR export default async function ComposersPage() { const composers = await getComposers(); return ( <div> <h1>作曲家列表</h1> <ul> {composers.map(composer => ( <li key={composer.id}>{composer.name}</li> ))} </ul> </div> ); }
验证静态生成是否生效
- 执行
npm run build,构建完成后查看.next/static/app/composers目录,若生成page.html文件则说明静态生成成功 - 启动生产服务
npm run start,查看页面响应头,若包含x-nextjs-cache: HIT则表示页面从静态缓存读取
关键注意事项
- App Router默认静态渲染,无需
getStaticProps,只要数据请求可缓存且无动态依赖(如用户会话、请求头) - 必须覆盖Supabase默认的禁止缓存响应头,否则无法实现静态预渲染
- 若页面使用
cookies()、headers()等动态API,会自动触发SSR,无法静态生成
内容的提问来源于stack exchange,提问作者vlovin
相关产品推荐
相关产品推荐

