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

如何修复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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 22:32:21