Docker容器间Next.js调用GraphQL服务时Apollo useQuery请求失败
问题解决:Next.js客户端无法访问Docker化的GraphQL服务(ERR_NAME_NOT_RESOLVED)
问题根源
核心矛盾在于服务器端与客户端的网络环境不统一:
- NextAuth、
getServerSideProps运行在Next.js容器内部,属于Docker共享网络,能通过容器名node正常访问GraphQL服务。 - 但
useQuery在用户浏览器中执行(客户端环境),浏览器不在Docker网络范围内,无法解析node这个Docker内部主机名,因此抛出ERR_NAME_NOT_RESOLVED错误。
解决方案
通过区分服务端/客户端的Apollo配置 + Nginx反向代理解决,步骤如下:
1. 修改ApolloClient配置,适配双环境
在Next.js中,通过typeof window === 'undefined'判断运行环境,服务器端用Docker内部地址访问GraphQL,客户端用相对路径交由Nginx转发:
function createLink(session?: Session | null) { // 判断是否为服务器端环境 const isServer = typeof window === 'undefined'; // 服务器端用Docker内部服务地址,客户端用相对路径 const authUrl = isServer ? "http://node_app:4000/graphql" : "/graphql"; const httpLink = new HttpLink({ uri: authUrl, }); const authLink = new ApolloLink((operation, forward) => { operation.setContext(({ headers = {} }) => ({ headers: { ...headers, ...(session?.accessToken ? { Authorization: `Bearer ${session?.accessToken}` } : {}), }, })); return forward(operation); }); return ApolloLink.from([authLink, httpLink]); } const createApolloClient = (session?: Session | null) => { return new ApolloClient({ link: createLink(session), cache: new InMemoryCache(), }); };
2. 修正Nginx配置,正确转发请求
之前的Nginx配置用localhost:4000是错误的——Nginx容器内部的localhost指向自身,而非宿主机器。需改用Docker服务名node_app访问GraphQL服务,同时配置Next.js请求转发:
server { listen 80; # 转发所有Next.js页面请求到next_app容器 location / { proxy_pass http://next_app:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 转发GraphQL请求到node_app容器 location /graphql { proxy_pass http://node_app:4000/graphql; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 确保Authorization等请求头被正确传递 proxy_pass_request_headers on; } }
3. Docker Compose配置优化(可选)
可以关闭next_app的3000端口对外暴露,所有请求统一通过Nginx转发:
next_app: build: ./next container_name: next # 移除对外的3000端口映射 # ports: # - 3000:3000 networks: - postgres-db-network volumes: - ./next:/app - /app/node_modules - /app/.next depends_on: - node_app environment: - NODE_ENV=development
方案原理
- 服务器端:Next.js容器处于Docker网络内,通过
node_app:4000直接访问GraphQL服务,原有认证逻辑保持正常运行。 - 客户端:浏览器通过相对路径
/graphql发送请求,Nginx将请求转发到GraphQL服务,既避免了跨域问题,也解决了Docker主机名无法解析的问题,同时Authorization令牌会被正确传递。
内容的提问来源于stack exchange,提问作者Sourouche
相关产品推荐
相关产品推荐

