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
相关产品推荐
相关产品推荐

