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

Next.js中getServerSideProps搭配Apollo报错:fetch failed

Next.js SSR中Apollo Client请求"failed to fetch"问题排查与解决

问题描述

我在Next.js中尝试通过服务端渲染(SSR)生成页面时遇到了failed to fetch错误。我创建了Apollo实例,从查询文件导入Query后,直接像客户端使用useQuery那样传递变量调用,但请求失败,想知道问题出在哪以及这类错误该怎么处理。

相关代码

getServerSideProps代码

export async function getServerSideProps(context) {
  const slug = context.params.slug;

  const data = await Static.query({
    query: LANDING,
    variables: { slug },
  });

  return {
    props: {
      data: data,
    },
  };
}

查询代码

import gql from "graphql-tag";

export const CATEGORIES = gql`
  query CategoriesView {
    CategoriesView {
      _id
      Name
      Description
      Icon
    }
  }
`;

Apollo客户端代码

import {
  ApolloClient,
  HttpLink,
  ApolloLink,
  InMemoryCache,
} from "@apollo/client";

const uri = "http://localhost:3000/api"

const httpLink = new HttpLink({uri});

export const Apollo = new ApolloClient({
  ssr: typeof window === "undefined" ? true : false,
  cache: new InMemoryCache(),
  link: ApolloLink.from([httpLink]),
});

问题排查与解决

1. 修正API URI配置

在SSR环境中,服务端请求本地API时,localhost:3000是服务端视角的本地地址,如果你的API是Next.js内置路由,可区分客户端/服务端的请求地址:

// 区分环境的URI配置
const uri = typeof window === "undefined" 
  ? "http://localhost:3000/api" // 服务端请求地址,部署到容器时需调整为服务内部地址
  : "/api"; // 客户端用相对路径即可

// 更推荐用环境变量,在.env.local中定义:
// NEXT_PUBLIC_API_URL=http://localhost:3000/api
// 代码中直接使用:const uri = process.env.NEXT_PUBLIC_API_URL;

2. 修正Apollo实例调用与错误捕获

代码中疑似存在笔误(Static.query应为Apollo.query),同时必须添加错误捕获避免页面崩溃:

export async function getServerSideProps(context) {
  try {
    const slug = context.params.slug;
    // 调用正确的Apollo实例
    const { data } = await Apollo.query({
      query: LANDING, // 注意:需确保该查询已正确导入,和你定义的CATEGORIES区分开
      variables: { slug },
    });

    return {
      props: {
        data,
      },
    };
  } catch (error) {
    // 打印错误日志便于排查
    console.error("SSR查询错误详情:", error);
    // 返回友好的错误处理逻辑,比如重定向到错误页
    return {
      redirect: {
        destination: "/error",
        permanent: false,
      },
    };
  }
}

3. SSR环境下Apollo客户端的最佳实践

避免服务端复用单例Apollo实例,建议创建初始化函数生成实例:

// apollo/client.js
import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client";

let apolloClient;

function createApolloClient() {
  const httpLink = new HttpLink({
    uri: process.env.NEXT_PUBLIC_API_URL,
    credentials: "include", // 若需要携带cookie请开启
  });

  return new ApolloClient({
    ssrMode: typeof window === "undefined",
    link: httpLink,
    cache: new InMemoryCache(),
  });
}

export function initializeApollo(initialState = null) {
  const _apolloClient = apolloClient ?? createApolloClient();

  // 服务端每次请求都生成新实例,避免跨请求污染
  if (typeof window === "undefined") return _apolloClient;
  // 客户端仅初始化一次实例
  if (!apolloClient) apolloClient = _apolloClient;

  return _apolloClient;
}

在getServerSideProps中使用:

import { initializeApollo } from "../apollo/client";

export async function getServerSideProps(context) {
  const apolloClient = initializeApollo();
  try {
    const slug = context.params.slug;
    const { data } = await apolloClient.query({
      query: LANDING,
      variables: { slug },
    });

    return {
      props: {
        initialApolloState: apolloClient.cache.extract(), // 传递缓存状态给客户端
        data,
      },
    };
  } catch (error) {
    console.error("SSR查询失败:", error);
    return {
      props: {
        error: "页面数据加载失败",
      },
    };
  }
}

通用错误处理建议

  • 始终用try/catch包裹服务端异步请求,避免未处理异常导致页面崩溃。
  • 服务端打印完整错误信息(包括错误栈、请求参数),快速定位问题。
  • 请求失败时,返回用户友好的处理逻辑(重定向错误页、前端展示提示)。
  • 提前验证服务端环境下API的可用性,比如用curl测试http://localhost:3000/api是否返回合法GraphQL响应。

内容的提问来源于stack exchange,提问作者nevoni3008

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 08:25:24