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

TypeScript集成ApolloServer订阅时applyMiddleware传参报错

报错根因

核心问题是导入的ApolloServer类来源错误:

  • 你当前从apollo-server包导入的ApolloServer是独立服务版本,内置了封装好的HTTP服务,本身不支持挂载到外部自定义的express实例上,它的applyMiddleware方法设计上就不接收任何参数,传入{app}自然会触发参数不合法的报错。
  • 凡是需要把Apollo Server挂载到自定义express实例、同时搭配WebSocket实现订阅的场景,都必须使用apollo-server-express包导出的ApolloServer类。

另外你现有代码还有两个隐藏的运行时问题:

  • 创建subscriptionServer的代码写在await server.start()之前,此时server.graphqlPath还未初始化,拿到的值是undefined,会导致订阅服务路径配置错误。
  • 初始化ApolloServer时同时传了schema和typeDefs两个配置项,二者是互斥的,你已经用makeExecutableSchema生成了完整schema实例,重复传typeDefs会造成配置冲突。
修复步骤
  1. 安装对应依赖包
npm install apollo-server-express
# yarn用户执行 yarn add apollo-server-express
  1. 修改ApolloServer的导入语句
// 删除原有错误导入
// import { ApolloServer } from "apollo-server";
// 替换为正确的导入源
import { ApolloServer } from "apollo-server-express";
  1. 调整代码执行顺序、移除冗余配置,修正后的核心代码如下
const run = async () => {
  dotenv.config();
  const pubsub = new PubSub();
  const db = await connectDB();
  const port = process.env.PORT;

  const app = express();
  const httpServer = createServer(app);
  const schema = makeExecutableSchema({
    typeDefs,
    resolvers: {
      Query,
      Mutation,
      // 记得补上Subscription对应的resolver,否则订阅逻辑不会生效
      // Subscription
    },
  });

  const server = new ApolloServer({
    schema,
    // 移除冗余的typeDefs配置
    context: ({ req, res }) => ({ req, res, pubsub }),
    plugins: [
      ApolloServerPluginDrainHttpServer({ httpServer }),
      {
        async serverWillStart() {
          return {
            async drainServer() {
              subscriptionServer.close();
            }
          };
        }
      }
    ],
  });

  // 先启动Apollo Server实例
  await server.start();

  // 再将服务挂载到自定义express实例,此时applyMiddleware可正常接收参数
  server.applyMiddleware({ app });

  // 最后初始化WebSocket订阅服务,此时server.graphqlPath已经是正确值
  const subscriptionServer = SubscriptionServer.create(
    {
      schema,
      execute,
      subscribe,
      async onConnect(connectionParams: any, webSocket: any, context: any) {
        console.log('Connected!');
        return { pubsub };
      },
      onDisconnect() {
        console.log('Disconnected!');
      }
    },
    {
      server: httpServer,
      path: server.graphqlPath,
    }
  );

  httpServer.listen(port, () => {
    console.log(
      `Server is now running on http://localhost:${port}${server.graphqlPath}`,
    );
  });
};

// 外层调用run时要加await,否则异步错误无法被catch捕获
try {
  await run();
} catch (error) {
  console.log(error);
}
额外注意事项
  • 补全resolvers中的Subscription相关解析逻辑,否则订阅功能无法正常工作。
  • 不要同时启用两套WebSocket订阅实现(比如你代码里注释掉的graphql-ws方案和当前用的subscriptions-transport-ws方案),不要让两个服务监听同一个路径,否则会产生协议冲突。
  • 如果你用的是Apollo Server 3.x版本,记得给express配置对应的CORS规则,否则前端访问会被跨域策略拦截。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 22:54:08