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

React+Next.js中如何通过Apollo Client关闭WebSocket订阅连接

解决Apollo Client订阅WebSocket连接无法关闭的问题

以下是几种在React/Next.js + TypeScript环境中正确关闭Apollo Client订阅WebSocket连接的方案,适配HotChocolate GraphQL服务器场景:

1. 组件内手动清理订阅实例

使用useSubscription时,保存订阅返回的引用,在组件卸载时调用取消方法:

import { useSubscription } from '@apollo/client';
import { useEffect, useRef } from 'react';
import { YOUR_SUBSCRIPTION_QUERY } from './graphql/queries';

const SubscriptionComponent = () => {
  const { subscribeToMore } = useSubscription(YOUR_SUBSCRIPTION_QUERY);
  const subscriptionRef = useRef<(() => void) | null>(null);

  useEffect(() => {
    if (subscribeToMore) {
      // 初始化订阅并保存取消引用
      subscriptionRef.current = subscribeToMore({
        document: YOUR_SUBSCRIPTION_QUERY,
        updateQuery: (prevData, { subscriptionData }) => {
          // 自定义数据更新逻辑
          return { ...prevData, ...subscriptionData.data };
        },
      });
    }

    // 组件卸载时执行清理
    return () => {
      subscriptionRef.current?.();
    };
  }, [subscribeToMore]);

  return <div>订阅内容展示...</div>;
};

export default SubscriptionComponent;

subscribeToMore返回的函数就是订阅的取消方法,调用它会直接关闭对应的WebSocket连接。

2. 全局管理SubscriptionClient并提供关闭方法

如果是手动创建WebSocketLink,可以在Apollo Client初始化时保存实例,提供全局关闭方法:

// lib/apollo-client.ts
import { ApolloClient, InMemoryCache, split, HttpLink } from '@apollo/client';
import { WebSocketLink } from '@apollo/client/link/ws';
import { getMainDefinition } from '@apollo/client/utilities';

let apolloClient: ApolloClient<any> | null = null;
let wsLink: WebSocketLink | null = null;

const createApolloClient = () => {
  const httpLink = new HttpLink({ uri: '/api/graphql' });

  wsLink = new WebSocketLink({
    uri: 'ws://localhost:5000/graphql',
    options: {
      reconnect: false, // 按需关闭自动重连,避免意外重连
      connectionParams: {
        authorization: `Bearer ${localStorage.getItem('token')}`,
      },
    },
  });

  const splitLink = split(
    ({ query }) => {
      const def = getMainDefinition(query);
      return def.kind === 'OperationDefinition' && def.operation === 'subscription';
    },
    wsLink,
    httpLink,
  );

  return new ApolloClient({
    ssrMode: typeof window === 'undefined',
    link: splitLink,
    cache: new InMemoryCache(),
  });
};

export const initializeApollo = () => {
  const _client = apolloClient ?? createApolloClient();
  if (typeof window === 'undefined') return _client;
  if (!apolloClient) apolloClient = _client;
  return _client;
};

// 暴露全局关闭WebSocket连接的方法
export const closeWsConnection = () => {
  wsLink?.subscriptionClient.close();
};

然后在页面或组件中,利用useEffect的清理逻辑调用该方法:

import { useEffect } from 'react';
import { closeWsConnection } from '../lib/apollo-client';

const SubscriptionPage = () => {
  useEffect(() => {
    return () => {
      closeWsConnection();
    };
  }, []);

  return <div>页面内容...</div>;
};

export default SubscriptionPage;

3. 监听Next.js路由变化自动关闭

在Next.js中,可以通过路由事件监听页面跳转,自动关闭连接:

import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { closeWsConnection } from '../lib/apollo-client';

const SubscriptionPage = () => {
  const router = useRouter();

  useEffect(() => {
    const handleRouteChange = () => closeWsConnection();

    router.events.on('routeChangeStart', handleRouteChange);

    return () => {
      router.events.off('routeChangeStart', handleRouteChange);
    };
  }, [router]);

  return <div>页面内容...</div>;
};

4. 优化HotChocolate服务器端配置

确保服务器端配置合理的连接超时,避免无效连接占用资源:

// Program.cs
builder.Services.AddGraphQLServer()
    .AddSubscriptionType<Subscription>()
    .AddInMemorySubscriptions()
    .ConfigureWebSocket(options =>
    {
        options.CloseTimeout = TimeSpan.FromSeconds(3); // 设置连接关闭超时
        options.KeepAliveInterval = TimeSpan.FromSeconds(10); // 心跳间隔,及时检测死连接
    });

内容的提问来源于stack exchange,提问作者David Marquardt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 10:07:41