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

GraphQL为createPost新增Subscription订阅无法连接WS服务问题

问题排查与修复方案

当前订阅连接失败由4个明确问题导致,按以下步骤修复即可:


1. 修复Schema语法错误

你的类型定义中Subscription部分存在语法错误:误将返回值的字段写为订阅参数,且缺失闭合大括号。替换为以下正确定义:

type Subscription {
  newPost: Post!
}

注意:newPost订阅的返回值是已定义的Post类型,不需要在订阅字段上重复声明Post的属性。


2. 修复WebSocket服务上下文配置

你之前仅给HTTP请求的上下文传入了pubsub实例,WebSocket连接的上下文未传入,会导致订阅resolver无法拿到pubsub对象触发事件。同时修正数据库连接的异步逻辑,避免服务启动时数据库未连接完成。
以下是修复后的完整index.js代码:

const { ApolloServer } = require ('apollo-server-express'); 
const { createServer } = require('http');
const express = require('express');
const { ApolloServerPluginDrainHttpServer } = require('apollo-server-core');
const { makeExecutableSchema } = require('@graphql-tools/schema');
const { WebSocketServer } = require('ws');
const { useServer } = require('graphql-ws/lib/use/ws');
const { PubSub } = require ('graphql-subscriptions'); 
const resolvers = require('./graphql/resolvers');
const typeDefs = require('./graphql/typeDefs');
const { MONGODB } = require('./config.js');
const mongoose = require('mongoose');

const pubsub = new PubSub();

(async function(){
  const schema = makeExecutableSchema({ typeDefs, resolvers });
  const app = express();
  const httpServer = createServer(app);

  const wsServer = new WebSocketServer({
    server: httpServer, 
    path: '/graphql'
  });

  // 给WS连接上下文注入pubsub实例
  const serverCleanup = useServer({ 
    schema,
    context: () => ({ pubsub })
  }, wsServer);

  const server = new ApolloServer({
    schema,
    csrfPrevention: true,
    cache: 'bounded',
    context: ({ req }) => ({ req, pubsub }),
    plugins: [
      ApolloServerPluginDrainHttpServer({ httpServer }),
      {
        async serverWillStart() {
          return {
            async drainServer() {
              await serverCleanup.dispose();
            },
          };
        },
      },
    ],
  });

  await server.start();
  server.applyMiddleware({ app });
  // 等待数据库连接完成再启动服务
  await mongoose.connect(MONGODB, {useNewUrlParser: true});
  console.log('MongoDB Connected');

  const PORT = 5002;
  httpServer.listen(PORT, () => {
    console.log(`HTTP endpoint: http://localhost:${PORT}${server.graphqlPath}`);
    console.log(`WS subscription endpoint: ws://localhost:${PORT}${server.graphqlPath}`);
  });
})();

3. 修复posts resolver语法错误

你之前的deletePost方法未写完整,缺失方法体和闭合大括号,会导致resolver模块加载失败。补全后代码如下:

const { AuthenticationError } = require('apollo-server');
const Post = require('../../models/Post');
const checkAuth = require('../../util/check-auth');

module.exports = {
  Mutation: {
    async createPost(_, { body }, context) {
      const user = checkAuth(context);
      // 可在此处补充你之前的帖子内容校验逻辑
      const newPost = new Post({
        body,
        user: user.id,
        username: user.username,
        createdAt: new Date().toISOString()
      });

      const post = await newPost.save();
      // 触发订阅事件
      context.pubsub.publish('NEW_POST', { newPost: post });
      console.log("New Post Created, Subscription Triggered!")

      return post;
    },
    async deletePost(_, { postId }, context) {
      const user = checkAuth(context);
      const post = await Post.findById(postId);
      if (!post) throw new Error('Post not found');
      if (post.username !== user.username) throw new AuthenticationError('No permission to delete this post');
      await post.delete();
      return 'Post deleted successfully';
    }
  },
  Subscription: {
    newPost: {
      subscribe: (_, __, { pubsub }) => pubsub.asyncIterator('NEW_POST')
    }
  }
};

4. 修正测试时的WS连接地址

你之前连接WS时用的是根路径ws://localhost:5002,正确的订阅地址是和HTTP端点一致的ws://localhost:5002/graphql,在Apollo Sandbox/Playground中配置订阅地址时填完整路径即可。


验证方法

  1. 启动服务后,在 playground 中先运行以下订阅语句,保持连接:
subscription {
  newPost {
    id
    body
    createdAt
    username
  }
}
  1. 新开一个标签页运行创建帖子的变更:
mutation {
  createPost(body: "test subscription post") {
    id
    body
  }
}
  1. 订阅标签页会自动收到新创建的帖子数据,即为配置成功。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:48:15