NextJs集成Apollo GraphQL Subscription时WebSocket报错如何解决
错误原因
- 报错的核心是Next.js存在服务端渲染(SSR/SSG)阶段,代码会先在Node.js服务端执行一次,而WebSocket仅在浏览器环境存在,服务端无原生实现
- 你的代码存在两个明显问题:
- 额外引入了仅Node.js环境使用的
ws库,浏览器端自带全局WebSocket对象,无需手动导入传入 - 未做环境区分,服务端运行时直接初始化了
wsLink,触发环境不兼容报错
- 额外引入了仅Node.js环境使用的
修复步骤
- 删除
import ws from 'ws';这行导入代码,同时删除WebSocketLink配置中传入的ws参数 - 增加环境判断逻辑,仅在浏览器环境(
typeof window !== 'undefined')下初始化wsLink,服务端直接使用httpLink处理所有请求 - 如果你使用的是Next.js 13+的App Router,需要在
client.js文件顶部添加'use client';标识,标记为客户端组件
完整修改后代码
// Next.js 13+ App Router 需要添加下面这行 // 'use client'; import { ApolloClient, ApolloLink, HttpLink, InMemoryCache, split, } from '@apollo/client'; import {WebSocketLink} from '@apollo/client/link/ws'; import {getMainDefinition} from '@apollo/client/utilities'; const httpUrl = 'http://localhost:3000/graphql'; const wsUrl = 'ws://localhost:3000/graphql'; const httpLink = ApolloLink.from([ new ApolloLink((operation, forward) => { return forward(operation); }), new HttpLink({uri: httpUrl}), ]); // 仅浏览器环境初始化wsLink let wsLink = null; if (typeof window !== 'undefined') { wsLink = new WebSocketLink({ uri: wsUrl, options: { connectionParams: () => {}, lazy: true, reconnect: true, } }); } function isSubscription(operation) { const definition = getMainDefinition(operation.query); return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' ); } const client = new ApolloClient({ cache: new InMemoryCache(), // 服务端无wsLink时直接走httpLink link: typeof window !== 'undefined' ? split(isSubscription, wsLink, httpLink) : httpLink, defaultOptions: {query: {fetchPolicy: 'no-cache'}}, }); export default client;
内容的提问来源于stack exchange,提问作者Tâm Đỗ
相关产品推荐
相关产品推荐

