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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 11:02:05