部署Next.js/TS/Sanity到Vercel时遇Fetch预渲染错误
问题原因
你遇到的错误核心是:在Next.js的getStaticProps中通过HTTP请求调用内部API端点,静态构建阶段(SSG)根本无法访问该API服务:
- 本地开发时,Next.js同时启动前端和API服务,
localhost:3000能正常访问API; - 部署到Vercel时,构建过程是独立的——此时API服务尚未启动,甚至已部署的应用地址在构建完成前还未生效,导致fetch请求直接失败。
解决方案:直接调用数据获取逻辑,跳过HTTP请求
不要绕圈子用fetch调用内部API,把API路由里的核心数据获取逻辑抽成共享函数,在getStaticProps和API路由里直接复用,彻底避开网络请求的问题。
步骤1:抽离共享的数据获取函数
创建一个共享文件(比如lib/sanity.ts),把从Sanity取数据的逻辑单独封装:
// lib/sanity.ts import { createClient } from '@sanity/client'; // 初始化Sanity客户端 const sanityClient = createClient({ projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID, dataset: process.env.NEXT_PUBLIC_SANITY_DATASET, apiVersion: '2023-05-03', // 使用最新API版本 useCdn: false, // 构建阶段禁用CDN,确保拿到最新数据 }); // 封装获取PageInfo的逻辑 export const getPageInfo = async () => { const query = `*[_type == "pageInfo"][0]`; const pageInfo = await sanityClient.fetch(query); return pageInfo; };
步骤2:修改API路由,复用共享函数
更新pages/api/getPageInfo.ts,直接调用刚才的共享函数,不用重复写数据获取逻辑:
// pages/api/getPageInfo.ts import type { NextApiRequest, NextApiResponse } from 'next'; import { getPageInfo } from '../../lib/sanity'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { const pageInfo = await getPageInfo(); res.status(200).json({ pageInfo }); } catch (error) { res.status(500).json({ error: '获取页面信息失败' }); } }
步骤3:修改你的fetchPageInfo函数
删掉原来的fetch请求,直接调用共享的getPageInfo函数:
// 导入共享函数 import { getPageInfo } from '../lib/sanity'; export const fetchPageInfo = async () => { const pageInfo = await getPageInfo(); return pageInfo; };
可选优化:直接在getStaticProps中调用
如果fetchPageInfo只是个中间层,也可以直接在getStaticProps里调用getPageInfo,减少冗余:
// pages/index.tsx import { getPageInfo } from '../lib/sanity'; export async function getStaticProps() { const pageInfo = await getPageInfo(); return { props: { pageInfo }, revalidate: 60, // 可选:设置静态页面自动重新验证的时间(秒) }; }
为什么这个方法有效?
getStaticProps是在构建阶段的服务器环境中运行的,直接调用本地TypeScript函数不需要经过HTTP请求,既解决了网络不可达的问题,又提升了构建效率。同时API路由依然能正常对外提供服务,不影响客户端侧的调用。
内容的提问来源于stack exchange,提问作者Endugu
相关产品推荐
相关产品推荐

