Next.js AppRouter部署Vercel时SSG调用内部API遇JSON解析错误
问题:Next.js应用部署到Vercel时构建失败,内部API调用报错
我有一个Next.js应用,代码如下:
export default async function StaticSiteGenerator() { const res = await fetch(`https://{DOMAIN_NAME}/api/data`); const data = await res.json(); return ( <div> <h1>Pokémon List</h1> <div style={{ display: "flex", flexWrap: "wrap" }}> {data.map((data: any, index: any) => ( <div key={index}> <p>{data.id}</p> </div> ))} </div> </div> ); }
将该应用部署到Vercel时,构建过程中出现如下错误:
SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON at JSON.parse (<anonymous>) at parseJSONFromBytes (node:internal/deps/undici/undici:5584:19) at successSteps (node:internal/deps/undici/undici:5555:27) at fullyReadBody (node:internal/deps/undici/undici:1665:9) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async specConsumeBody (node:internal/deps/undici/undici:5564:7) at async i (/vercel/path0/.next/server/app/extra/ssg/page.js:1:4401) { digest: '3318096297' }
我倾向于使用内部API(而非server actions或其他替代方案),该如何解决此问题以确保构建成功?
我怀疑错误是因构建时内部API尚未就绪导致的,有趣的是本地构建完全正常。
解决方案
核心原因
你的猜测正确:Vercel静态构建阶段,应用还未部署上线,https://{DOMAIN_NAME}/api/data指向的服务尚未启动,请求返回的是404页面的HTML(即错误中的<!DOCTYPE...),而非预期的JSON,因此解析失败。本地构建正常是因为本地开发服务器同时运行了前端和API路由,请求能正常命中。
解决方法(使用内部API的正确姿势)
方案1:直接调用API路由的服务器端逻辑(推荐)
在Next.js中,无需通过HTTP请求访问外部域名,直接调用API路由的核心逻辑即可:
抽离API逻辑到独立文件
假设你的/api/data路由代码在app/api/data/route.ts,把数据获取逻辑抽离到公共文件:// app/lib/data.ts export async function getPokemonData() { // 这里放置原本/api/data路由中的业务逻辑,比如从数据库或外部数据源拉取数据 const response = await fetch("https://pokeapi.co/api/v2/pokemon?limit=10"); const data = await response.json(); return data.results; }在页面组件中直接调用该函数
修改页面组件,替换HTTP请求为直接调用逻辑函数:import { getPokemonData } from "@/app/lib/data"; export default async function StaticSiteGenerator() { const data = await getPokemonData(); return ( <div> <h1>Pokémon List</h1> <div style={{ display: "flex", flexWrap: "wrap" }}> {data.map((item: any, index: number) => ( <div key={index}> <p>{item.name}</p> </div> ))} </div> </div> ); }
方案2:保留HTTP调用(不推荐,仅满足需求)
如果坚持要通过HTTP请求内部API,可以在构建阶段使用相对路径或环境判断,但需注意构建阶段的局限性:
export default async function StaticSiteGenerator() { // 构建阶段使用本地地址,生产环境用正式域名 const baseUrl = process.env.NODE_ENV === "production" ? "https://{DOMAIN_NAME}" : "http://localhost:3000"; const res = await fetch(`${baseUrl}/api/data`); // 先校验响应状态,避免解析失败 if (!res.ok) { throw new Error(`API请求失败: ${res.status}`); } const data = await res.json(); return ( <div> <h1>Pokémon List</h1> <div style={{ display: "flex", flexWrap: "wrap" }}> {data.map((data: any, index: any) => ( <div key={index}> <p>{data.id}</p> </div> ))} </div> </div> ); }
注意:这种方法在Vercel静态构建时仍可能失败,因为构建阶段API服务未启动,因此方案1是更可靠的选择。
额外提示
- 静态生成页面的数据获取,优先使用服务器端直接逻辑调用,既高效又能避免网络请求的不确定性。
- 若必须调用外部HTTP API,确保该API在构建阶段是独立部署且始终可用的。
内容的提问来源于stack exchange,提问作者user25401403
相关产品推荐
相关产品推荐

