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

Vue+Apollo Client连接GraphQL服务器WebSocket失败求助

排查WebSocket连接失败(Websocket failed to Connect)问题

问题概述

客户端与服务器端均出现「WebSocket failed to Connect」错误,仅通过Apollo Client配置WebSocket连接,无其他相关配置,问题已持续2天。环境为Vue客户端连接GraphQL Apollo服务器。

相关代码

ApolloClient配置

// Apollo packages
import { ApolloClient } from "apollo-boost-upload";
import { WebSocketLink } from "apollo-link-ws";
import { HttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
import { split } from "apollo-link";
import { getMainDefinition } from "apollo-utilities";
import VueApollo from "vue-apollo";
Vue.use(VueApollo);    

const wsLink = new WebSocketLink({
  uri: "ws://localhost:4000/graphql", // use wss for a secure endpoint
  options: {
    reconnect: true,
  },
});

// 注意:原代码缺少httpLink的初始化,需补充
const httpLink = new HttpLink({
  uri: "http://localhost:4000/graphql",
  credentials: "include"
});

const link = split(
  // split based on operation type
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === "OperationDefinition" &&
      definition.operation === "subscription"
    );
  },
  wsLink,
  httpLink
);

// Cache implementation
    
export const defaultClient = new ApolloClient({
  link,
  cache: new InMemoryCache(),
  fetchOptions: {
    credentials: "include",
  },
 
  request: (operation) => {
    // if no token in local storage, add it
    if (!localStorage.anaceptToken) {
      localStorage.setItem("anaceptToken", "");
    }
    // operation adds the token to authorization header, which is sent to backend
    operation.setContext({
      headers: {
        authorization: "Bearer " + localStorage.getItem("anaceptToken"),
      },
    });
  },
  onError: ({ graphQLErrors, networkError }) => {
    if (networkError) {
      console.log("[networkError]", networkError);
    }
    if (graphQLErrors) {
      for (const error of graphQLErrors) {
        console.dir(error);
        console.log(error);
        if (
          error.name === "AuthenticationError" ||
          error.message === "jwt expired"
        ) {
          // set auth error in state
          store.commit("setError", error);
          // signout user to clear error
          store.dispatch("signUserOut");
        }
      }
    }
  },
});

Vue配置文件

const { defineConfig } = require("@vue/cli-service");
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
module.exports = defineConfig({
  pluginOptions: {
    apollo: {
      enableMocks: true,
      enableEngine: true,
    },
  },
  transpileDependencies: ["vuetify"],
  chainWebpack: (config) => {
    config.performance.maxEntrypointSize(400000).maxAssetSize(400000);
    // 修正插件注册方式,原写法不会生效
    config.plugin('node-polyfill').use(NodePolyfillPlugin);
  },
});

错误截图

WebSocket连接失败错误截图

排查与修复步骤

  • 补全httpLink初始化:原代码未实例化httpLink,会导致链路拆分逻辑失效,必须添加上述代码中的httpLink初始化部分。
  • 验证服务器WebSocket配置:确认Apollo Server已启用WebSocket支持(如使用subscriptions-transport-ws或graphql-ws库),且ws://localhost:4000/graphql端点可正常访问。
  • 添加WebSocket的token传递:WebSocket连接不会自动继承HTTP请求的头信息,需在WebSocketLink的options中配置connectionParams传递token:
    const wsLink = new WebSocketLink({
      uri: "ws://localhost:4000/graphql",
      options: {
        reconnect: true,
        connectionParams: {
          authorization: "Bearer " + localStorage.getItem("anaceptToken"),
        },
      },
    });
    
  • 修正Webpack插件配置:原chainWebpack中直接new NodePolyfillPlugin无法正确注册插件,需改用config.plugin方式添加。
  • 检查端口与跨域:确保4000端口未被占用,服务器已配置允许WebSocket的跨域规则(如CORS设置包含WebSocket相关允许项)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 21:41:11