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
相关产品推荐
相关产品推荐

