You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js部署Vercel预渲染报错:ECONNREFUSED 127.0.0.1:3000

问题:Next.js部署到Vercel时主页预渲染失败

本地开发环境运行正常,但部署到Vercel后出现以下错误:

页面"/"预渲染时发生错误。
FetchError: 请求http://localhost:3000/api/getPageInfo失败,原因:connect ECONNREFUSED 127.0.0.1:3000

本地可正常访问http://localhost:3000/api/getPageInfo接口,已在Vercel配置以下环境变量:

  • NEXT_PUBLIC_BASE_URL = http://localhost:3000
  • NEXT_PUBLIC_SANITY_DATASET = production
  • NEXT_PUBLIC_SANITY_PROJECT_ID

相关代码片段:

// api/getExperience.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { groq } from 'next-sanity';
import { sanityClient } from "../../sanity";
import { Experience } from "../../typings";

const query = groq`
    *[_type == 'experience'] {
        ...,
        technologies[]-> 
    }
`;

type Data = {
    experiences: Experience[];
}

export default async function handler(
    req: NextApiRequest,
    res: NextApiResponse<Data>
) {
    const experiences: Experience[] = await sanityClient.fetch(query);
    res.status(200).json({ experiences })
}
// utils/fetchExperiences.ts
import { Experience } from '../../typings';

export const fetchExperiences = async() => {
        const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/getExperience`);
    
        const data = await res.json()
        const experiences: Experience[] = data.experiences;
        
        return experiences;
}
// pages/index.tsx
export const getStaticProps: GetStaticProps<Props> = async () => {
  const pageInfo: PageInfo = await fetchPageInfo();
  const experiences: Experience[] = await fetchExperiences();
  const skills: Skill[] = await fetchSkills();
  const projects: Project[] = await fetchProjects();
  const socials: Social[] = await fetchSocials();

  return { 
    props: {
      pageInfo,
      experiences,
      skills,
      projects,
      socials,
    },
    revalidate: 10,
  }
}

解决方案

错误核心原因

  1. Vercel构建阶段并未启动localhost:3000服务,此时通过fetch请求本地API必然失败
  2. NEXT_PUBLIC_BASE_URL硬编码为localhost:3000,生产环境中无法指向正确的Vercel域名
  3. 通过API路由中转Sanity请求属于冗余环节,增加了不必要的网络开销

修复方案

方案1:直接在getStaticProps中调用Sanity客户端(推荐)

跳过API路由层,直接在服务器端的getStaticProps里用sanityClient拉取数据,彻底避免内部请求问题:

// pages/index.tsx
import { sanityClient } from '../sanity';
import { groq } from 'next-sanity';
import { PageInfo, Experience, Skill, Project, Social } from '../typings';

// 定义各数据类型的GROQ查询
const pageInfoQuery = groq`*[_type == "pageInfo"][0]`;
const experiencesQuery = groq`*[_type == 'experience'] {..., technologies[]-> }`;
const skillsQuery = groq`*[_type == 'skill']`;
const projectsQuery = groq`*[_type == 'project'] {..., technologies[]-> }`;
const socialsQuery = groq`*[_type == 'social']`;

export const getStaticProps: GetStaticProps<Props> = async () => {
  // 直接通过sanityClient获取数据
  const pageInfo: PageInfo = await sanityClient.fetch(pageInfoQuery);
  const experiences: Experience[] = await sanityClient.fetch(experiencesQuery);
  const skills: Skill[] = await sanityClient.fetch(skillsQuery);
  const projects: Project[] = await sanityClient.fetch(projectsQuery);
  const socials: Social[] = await sanityClient.fetch(socialsQuery);

  return { 
    props: { pageInfo, experiences, skills, projects, socials },
    revalidate: 10,
  }
}

方案2:保留API路由时的修正(适合必须保留API层的场景)

  1. 区分环境配置BASE_URL

    • 本地.env.local:NEXT_PUBLIC_BASE_URL=http://localhost:3000
    • Vercel环境变量:NEXT_PUBLIC_BASE_URL=https://你的Vercel域名.vercel.app
  2. 服务器端fetch改用相对路径
    Next.js在服务器端执行fetch时,会自动解析相对路径为内部路由,无需依赖环境变量:

    export const fetchExperiences = async() => {
      const res = await fetch('/api/getExperience');
      const data = await res.json();
      return data.experiences;
    }
    

额外优化建议

  • 若Sanity的项目ID和数据集无需在客户端代码中使用,去掉NEXT_PUBLIC_前缀,仅在服务器端访问,提升安全性
  • 优先选择直接在数据获取函数中调用数据源,减少不必要的API中转环节

内容的提问来源于stack exchange,提问作者Antônio Miguel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 01:01:12