如何修复Apollo Server+SQL Server环境下WebSocket订阅连接失败问题?
问题描述
我正在使用Apollo Server构建包含Query、Subscription和Mutation的GraphQL服务,搭配SQL Server数据库。已成功实现Query功能,通过HTTP链接进入Apollo Sandbox可正常查询,但在React应用中使用urql的GraphQLWsLink连接服务端WebSocket链接时,出现“Failed to connect to websocket”错误。
服务端WebSocket配置代码
const {createServer} = require('http'); const {ApolloServerPluginDrainHttpServer} = require('apollo-server-core'); const {ApolloServerPluginLandingPageLocalDefault} = require('apollo-server-core'); const {makeExecutableSchema} = require('@graphql-tools/schema'); const {WebSocketServer} = require('ws'); const {useServer} = require('graphql-ws/lib/use/ws'); const { ApolloServer,gql } = require('apollo-server'); var http = require("http"); const fs = require('fs'); const resolvers = require('./graphql/resolvers'); const typeDefs = gql(fs.readFileSync('./graphql/typeDefs.graphql',{encoding:'utf-8'})); console.log("Resolvers", resolvers) const app = new ApolloServer({typeDefs,resolvers }); const schema = makeExecutableSchema({ typeDefs, resolvers }); // ... const httpServer = createServer(app); // Creating the WebSocket server const wsServer = new WebSocketServer({ server: httpServer, path: '/graphql', }); const serverCleanup = useServer({ schema }, wsServer); const server = new ApolloServer({ schema, csrfPrevention: true, cache: "bounded", plugins: [ // Proper shutdown for the HTTP server. ApolloServerPluginDrainHttpServer({ httpServer }), // Proper shutdown for the WebSocket server. { async serverWillStart() { return { async drainServer() { await serverCleanup.dispose(); }, }; }, }, ApolloServerPluginLandingPageLocalDefault({ embed: true }), ], }); server.listen(5000).then(({ url }) => { console.log("Server ready at " + url ); });
客户端(React)代码
const serverURL = "http://127.0.0.1:5000/graphql"; const wsClient = new GraphQLWsLink(createClient({ url: 'ws://127.0.0.1:5000/graphql', })); const client = createClient({ url: senseopsHTTPServerURL, exchanges: [ ...defaultExchanges, subscriptionExchange({ forwardSubscription: (operation) => ({ subscribe: (sink) => ({ unsubscribe: wsClient.subscribe(operation, sink), }), }), }), ], });
修复方案
1. 移除重复的ApolloServer实例
代码中创建了两个ApolloServer实例,第一个app实例完全多余,会干扰WebSocket服务的正确挂载,直接删除该行:
// 删掉这一行 // const app = new ApolloServer({typeDefs,resolvers });
2. 修正服务端启动方式
ApolloServer的listen()方法会自动创建新的HTTP服务器,和你手动创建的httpServer冲突,导致WebSocket服务无法绑定到正确的服务器。改为先启动ApolloServer,再启动手动创建的HTTP服务器:
// 替换原来的 server.listen(5000)... server.start().then(() => { httpServer.listen(5000, () => { console.log("Server ready at http://127.0.0.1:5000/graphql"); }); });
3. 修正客户端地址配置
客户端中senseopsHTTPServerURL未定义,替换为正确的serverURL:
const client = createClient({ url: serverURL, // 替换为正确的HTTP地址 exchanges: [ ...defaultExchanges, subscriptionExchange({ forwardSubscription: (operation) => ({ subscribe: (sink) => ({ unsubscribe: wsClient.subscribe(operation, sink), }), }), }), ], });
同时确保已安装@urql/exchange-graphql-ws依赖:
npm install @urql/exchange-graphql-ws
4. 配置CORS(解决跨域问题)
如果React应用运行在不同端口,需在ApolloServer中添加CORS配置,允许WebSocket请求:
const server = new ApolloServer({ schema, csrfPrevention: true, cache: "bounded", cors: { origin: "http://localhost:3000", // 你的React应用地址 credentials: true, }, plugins: [/* 原有插件配置 */], });
5. 验证WebSocket服务可用性
用wscat工具测试服务端WebSocket是否正常:
npm install -g wscat wscat -c ws://127.0.0.1:5000/graphql
若连接成功,说明服务端没问题,继续排查客户端;若失败,回到服务端检查配置。
内容的提问来源于stack exchange,提问作者Nvv
相关产品推荐
相关产品推荐

