App Router下动态页面为何在构建阶段发起请求?
为什么Next.js动态页面在构建阶段也会执行数据请求,且多次触发?
构建阶段触发两次请求的原因
- 元数据预渲染逻辑:你在
generateMetadata里调用了getData,Next.js为了提前生成SEO所需的页面元数据(标题、描述),会在构建阶段执行这个函数。哪怕页面是动态的,只要元数据不依赖cookies、请求参数这类动态上下文,Next.js就会尝试在构建时预生成它,这是第一次数据请求的来源。 - 动态页面的预渲染尝试:你的页面因为使用了
cookies(),被标记为「按需SSR」的动态页面,但Next.js在构建时仍会尝试预渲染页面一次,验证是否能生成静态内容。由于构建环境中没有access-token这个cookie,代码会走到const data = await getData()这一步,触发第二次数据请求。
用户访问时再次触发请求的原因
当用户访问页面时,因为页面依赖动态上下文(cookies),Next.js会在服务器端重新渲染整个页面:
- 首先调用
generateMetadata生成当前请求对应的元数据(动态页面的元数据不会复用构建时的结果,会在每次请求时重新生成); - 然后渲染
Page组件,再次调用getData。
所以每次用户访问都会触发两次数据请求。
解决方法
1. 同一请求内复用数据,避免重复请求
用React.cache包裹getData,让同一个请求内的多次调用共享同一份数据结果,减少实际发起的网络请求:
import { cache } from 'react'; const getData = cache(async () => { try { const res = await getDataWithAxios<MockoonResponse>({ method: "get", params: { whatever: "123", }, endpoint: "http://127.0.0.1:4003/api/mockoontest", }); return res; } catch (error) { console.error(error); } });
2. 阻止构建阶段的元数据预生成
如果不需要在构建阶段生成元数据,可以让generateMetadata依赖动态上下文,比如读取cookies,让Next.js知道这是动态元数据,不会在构建时预生成:
export async function generateMetadata() { // 读取cookies,标记元数据为动态 cookies(); const res = await getData(); return { title: res?.seo.title, description: res?.seo.description, }; }
3. 禁用页面的构建预渲染尝试
添加export const dynamic = 'force-dynamic',明确标记页面为完全动态,Next.js就不会在构建时尝试预渲染页面,彻底避免构建阶段的页面侧数据请求:
export const dynamic = 'force-dynamic'; // 其余代码不变
内容的提问来源于stack exchange,提问作者Professor Chaos
相关产品推荐
相关产品推荐

