NextJS中GraphQL useSubscription结合GraphQLWsLink失效求助
排查Next.js中GraphQLWsLink订阅无数据返回的问题
针对你遇到的GraphQLWsLink连接成功但无订阅数据返回、网络面板无请求载荷的问题,结合提供的配置代码,下面给出具体排查方向和修复方案:
核心差异分析
graphql-ws(对应GraphQLWsLink)使用的是标准GraphQL over WebSocket协议,而旧的subscriptions-transport-ws是自定义订阅协议,两者不兼容。首先要确认服务器是否支持graphql-ws的协议标准。
具体排查步骤
1. 验证服务器协议支持
如果服务器仅配置了旧的subscriptions-transport-ws支持,即使WebSocket连接能建立,也无法处理graphql-ws格式的订阅请求:
- 对于Apollo Server,需安装
@apollo/server-plugin-subscriptions并启用订阅插件,或使用graphql-ws官方提供的服务器适配器。 - 查看服务器日志,确认是否收到
graphql-ws格式的请求并返回响应。
2. 排查鉴权参数问题
你的GraphQLWsLink配置中添加了Authorization参数,但旧配置没有,可能是鉴权失败导致服务器拒绝订阅:
- 暂时注释
connectionParams中的Authorization,测试基础订阅是否正常:connectionParams: () => { // 先移除鉴权,验证订阅逻辑本身是否正常 return {}; }, - 打印
connectionParams的返回值,确认session.token是否为有效令牌:connectionParams: () => { const token = session.token; console.log('连接参数:', { Authorization: `Bearer ${token}` }); return { Authorization: `Bearer ${token}`, }; },
3. 添加详细日志定位问题
在graphql-ws客户端配置中补充详细日志,查看服务器交互细节:
on: { closed: () => console.log("CLOSED"), ping: () => console.log("ping"), pong: () => console.log("pong"), connected: () => console.log("connected"), connecting: () => console.log("connecting"), error: (err) => console.log("WebSocket错误:", err), // 打印具体错误信息 message: (msg) => console.log("收到服务器消息:", msg), // 打印完整消息内容 opened: () => console.log("opened"), },
- 如果
on.error触发,说明服务器返回了错误(比如鉴权失败、订阅字段不存在)。 - 如果
on.message收到内容,可直接查看是否包含订阅数据或错误提示。
4. 优化Next.js中的Client创建
在Next.js中,避免重复创建WebSocket客户端,用useMemo缓存实例以保证稳定性:
修改你的useApolloClient hook:
import { useMemo } from 'react'; import { split, HttpLink, ApolloClient, InMemoryCache } from "@apollo/client"; import { getMainDefinition } from "@apollo/client/utilities"; import { GraphQLWsLink } from "@apollo/client/link/subscriptions"; import { createClient } from "graphql-ws"; export const useApolloClient = () => { // 缓存HttpLink实例 const httpLink = useMemo(() => new HttpLink({ uri: process.env.NEXT_PUBLIC_GRAPHQL_API_URL, }), []); // 仅在客户端环境创建WebSocket链接并缓存 const wsLink = useMemo(() => { if (typeof window === 'undefined') return null; return new GraphQLWsLink( createClient({ url: process.env.NEXT_PUBLIC_GRAPHQL_SOCKET_URL, shouldRetry: true, connectionParams: () => { const token = session.token; return { Authorization: `Bearer ${token}`, }; }, on: { closed: () => console.log("CLOSED"), ping: () => console.log("ping"), pong: () => console.log("pong"), connected: () => console.log("connected"), connecting: () => console.log("connecting"), error: (err) => console.log("WebSocket错误:", err), message: (msg) => console.log("收到服务器消息:", msg), opened: () => console.log("opened"), }, }) ); }, []); // 拆分链接并缓存 const splitLink = useMemo(() => { if (!wsLink) return httpLink; return split( ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === "OperationDefinition" && definition.operation === "subscription" ); }, wsLink, httpLink ); }, [wsLink, httpLink]); // 缓存ApolloClient实例 const client = useMemo(() => new ApolloClient({ link: splitLink, cache: new InMemoryCache(), }), [splitLink]); return client; };
5. 检查Apollo Client版本
确保@apollo/client版本 >= 3.7.0,GraphQLWsLink是在该版本后正式集成到Apollo Client中的,低版本可能存在兼容性问题。
6. 查看订阅组件状态
打开订阅页面中被注释的状态显示代码,查看loading、data、error的具体值:
const { loading, data, error } = useSubscription(SUBSCRIPTION_ADD_COMMENT, { onComplete: () => console.log(">>>>>>>>>>>>> Subscription onCOmplete"), onData: ({ data }) => console.log(">>>>>>>>>>>>> Subscription onData", data), onError: (err) => console.log(">>>>>>>>>>>>> Subscription onError", err), }); return ( <div> <h1>{loading ? "LOADING" : "ENDED"}</h1> <h1>{data ? JSON.stringify(data) : "NO DATA"}</h1> <h1>{error ? JSON.stringify(error) : "NO Error"}</h1> </div> );
总结
最可能的原因是:
- 服务器未支持
graphql-ws标准协议; connectionParams中的鉴权令牌无效;- WebSocket客户端重复创建导致订阅请求未正确发送。
按照上述步骤逐一排查,应该能定位并解决问题。
内容的提问来源于stack exchange,提问作者Tamil Vanan
相关产品推荐
相关产品推荐

