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

GraphQL订阅无法连接WebSocket端点问题求助

GraphQL订阅WebSocket连接失败问题排查

问题描述

我是GraphQL新手,尝试创建订阅功能时出现以下错误:

无法连接到WebSocket端点ws://localhost:3000/graphql。请检查端点URL是否正确。

参考官方文档编写的代码如下:

const { createServer } = require('http')
const express = require('express')
const { ApolloServer } = require('apollo-server-express')
const { ApolloServerPluginDrainHttpServer } = require('apollo-server-core')
const { PubSub } = require('graphql-subscriptions')
const { WebSocketServer } = require('ws')
const { useServer } = require('graphql-ws/lib/use/ws')
const { env } = require('../config/index')
const schema = require('./schema')
const models = require('../db/models')
const getAuthUser = require('../utils/authorization')

const pubSub = new PubSub()
const app = express()
const httpServer = createServer(app)
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()
                    },
                }
            },
        },
    ],
    playground: env.development,
    context: async ({ req }) => {
        const token = req.headers.authorization
        const user = getAuthUser(token)
        return { models, user, pubSub }
    },
})
server.applyMiddleware({ app })
server.installSubscriptionHandlers(httpServer)
module.exports = { server, httpServer }

另一文件中已调用httpServer.listen(port)启动服务,请问该错误产生的原因是什么?有哪些解决建议?

可能的原因

  • 重复配置WebSocket服务:同时使用graphql-ws的useServer和Apollo Server的installSubscriptionHandlers,两种方式均用于配置WebSocket订阅服务,会引发端口冲突或服务启动异常。Apollo Server 3+推荐使用graphql-ws集成方式,installSubscriptionHandlers属于旧版订阅处理方法,二者共存会造成冲突。
  • WebSocket上下文缺失:当前context函数仅处理HTTP请求的req对象,但WebSocket连接的上下文需要单独处理。若未在graphql-ws的配置中定义上下文逻辑,可能导致连接时权限验证或数据获取失败,间接引发连接问题。
  • 端口/路径不匹配:若httpServer.listen(port)中的port并非3000,或3000端口被其他程序占用,会导致客户端无法连接到指定端点。

解决建议

  • 移除重复订阅配置:删除server.installSubscriptionHandlers(httpServer)代码行,已通过graphql-ws的useServer完成WebSocket服务配置,无需保留旧版处理逻辑。
  • 完善WebSocket上下文处理:在useServer配置中添加context选项,处理WebSocket连接的上下文(比如从连接参数中获取token):
const serverCleanup = useServer({
  schema,
  context: async (ctx) => {
    const token = ctx.connectionParams?.authorization;
    const user = getAuthUser(token);
    return { models, user, pubSub };
  },
}, wsServer);
  • 验证端口与路径:确认httpServer.listen(port)中的port为3000,或修改客户端连接URL为实际端口。检查端口占用情况:
    • Mac/Linux:运行lsof -i :3000
    • Windows:运行netstat -ano | findstr :3000
      若端口被占用,更换为未被使用的端口。
  • 检查依赖版本兼容性:确保apollo-server-express、graphql-ws等依赖版本兼容。Apollo Server 3.x需搭配graphql-ws,而非旧版的subscriptions-transport-ws。运行npm list查看依赖版本,必要时更新至兼容版本。

内容的提问来源于stack exchange,提问作者Garth McCallister

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 22:03:31