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

Apollo 2.x客户端与服务器订阅配置:WebSocket握手错误400

解决Apollo 2.x订阅功能WebSocket握手400错误的方案

嘿,我之前在折腾Apollo 2.x订阅功能时,也碰到过一模一样的WebSocket握手400错误,咱们一步步来排查解决!

1. 先核对客户端与服务器的订阅端点路径是否一致

这是最常见的问题!你客户端连的是ws://localhost:3200/,但很多时候Apollo Server会把订阅端点挂在/graphql路径下,而不是根路径。

  • 服务器端检查:看看你的SubscriptionServer配置里的path参数,比如:
    SubscriptionServer.create(
      { schema, execute, subscribe },
      { server: httpServer, path: '/graphql' } // 这里的path就是订阅端点路径
    );
    
  • 客户端修正:如果服务器路径是/graphql,那客户端的WebSocket链接URI要改成ws://localhost:3200/graphql,而不是只写localhost:3200。

2. 确保服务器端正确整合HTTP服务器与SubscriptionServer

Apollo 2.x的订阅功能需要把SubscriptionServer附着在HTTP服务器实例上,而不是直接用Express的app.listen启动,否则WebSocket握手会失败。

正确的服务器启动示例:

import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import { createServer } from 'http';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import { execute, subscribe } from 'graphql';
import schema from './schema';

const app = express();
const httpServer = createServer(app); // 先创建HTTP服务器实例

// 挂载Apollo Server
const apolloServer = new ApolloServer({ schema });
apolloServer.applyMiddleware({ app });

// 附着SubscriptionServer到HTTP服务器
SubscriptionServer.create(
  { schema, execute, subscribe },
  { server: httpServer, path: '/graphql' }
);

// 用HTTP服务器实例启动,而不是app.listen
httpServer.listen(3200, () => {
  console.log(`HTTP服务运行在 http://localhost:3200${apolloServer.graphqlPath}`);
  console.log(`订阅端点就绪:ws://localhost:3200/graphql`);
});

3. 检查CORS配置是否覆盖WebSocket请求

如果你的客户端和服务器端口不同(比如客户端跑在3000,服务器在3200),CORS配置可能会阻止WebSocket握手。

  • 在Apollo Server里直接配置CORS:
    const apolloServer = new ApolloServer({ 
      schema,
      cors: {
        origin: 'http://localhost:3000', // 替换成你的客户端地址
        credentials: true
      }
    });
    
  • 或者在Express里提前配置CORS中间件,确保包含WebSocket的路径:
    import cors from 'cors';
    app.use(cors({ origin: 'http://localhost:3000', credentials: true }));
    

4. 排查网络拦截因素

  • 关闭浏览器的代理插件(比如AdBlock、VPN),或者用无痕模式测试,避免插件拦截WebSocket请求。
  • 检查本地防火墙是否阻止了3200端口的WebSocket连接,或者看看有没有其他程序占用了3200端口。

5. 客户端WebSocket链接的正确配置示例

确保你的Apollo Client正确整合了WebSocket链接,拆分HTTP和WS请求:

import React from "react";
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { split } from 'apollo-link';
import { HttpLink } from 'apollo-link-http';
import { WebSocketLink } from 'apollo-link-ws';
import { getMainDefinition } from 'apollo-utilities';

// HTTP链接处理查询和变更
const httpLink = new HttpLink({ uri: 'http://localhost:3200/graphql' });

// WebSocket链接处理订阅
const wsLink = new WebSocketLink({
  uri: 'ws://localhost:3200/graphql', // 必须和服务器路径一致
  options: {
    reconnect: true, // 断开自动重连
    connectionParams: {
      // 如果需要认证,在这里传token等参数
    }
  }
});

// 拆分链接:根据操作类型选择HTTP或WS
const link = split(
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
    );
  },
  wsLink,
  httpLink
);

// 创建Apollo Client实例
const client = new ApolloClient({
  link,
  cache: new InMemoryCache()
});

先从路径匹配和服务器启动方式这两点入手排查,这两个是最容易出错的地方,大概率能解决你的400错误!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:32:40