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

如何在@apollo/client与apollo-server-express的GraphQL订阅中传递Header

解决Apollo Client WebSocketLink传递自定义Header到Apollo Server订阅的问题

客户端配置(@apollo/client)

需要在创建WebSocketLink时,通过options.connectionParams配置自定义Header,这部分参数会在WebSocket握手阶段发送给服务端:

import { WebSocketLink } from '@apollo/client/link/ws';
import { split, HttpLink } from '@apollo/client';
import { getMainDefinition } from '@apollo/client/utilities';
import { InMemoryCache, ApolloClient } from '@apollo/client';

// 创建WebSocket链接
const wsLink = new WebSocketLink({
  uri: 'ws://your-server-url/graphql',
  options: {
    reconnect: true,
    // 配置握手时传递的参数
    connectionParams: {
      headers: {
        'X-Auth-Token': 'my-auth-token',
      },
    },
    // 如果token是动态获取的,可改为函数形式
    // connectionParams: () => ({
    //   headers: {
    //     'X-Auth-Token': localStorage.getItem('auth-token'),
    //   },
    // }),
  },
});

// 创建HTTP链接(用于查询/突变操作)
const httpLink = new HttpLink({
  uri: 'http://your-server-url/graphql',
});

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

// 初始化Apollo Client
const client = new ApolloClient({
  link: splitLink,
  cache: new InMemoryCache(),
});

之后调用client.subscribe时无需额外设置context,握手阶段已经传递了Header信息:

const sub = await client.subscribe({
  query: MY_SUBSCRIPTION,
  variables: {
    // 你的订阅变量
  },
});

服务端配置(apollo-server-express)

需要在ApolloServer的subscriptions选项中添加onConnect回调,将客户端传递的connectionParams注入到上下文,这样订阅Resolver就能获取到Header:

const { ApolloServer } = require('apollo-server-express');
const express = require('express');

const app = express();

const server = new ApolloServer({
  typeDefs, // 你的GraphQL类型定义
  resolvers, // 你的Resolver
  subscriptions: {
    onConnect: (connectionParams) => {
      // 将客户端传递的headers存入上下文
      return {
        headers: connectionParams.headers,
      };
    },
  },
});

// 应用中间件并安装订阅处理器
server.applyMiddleware({ app });
server.installSubscriptionHandlers(app);

app.listen({ port: 4000 }, () => {
  console.log(`Server ready at http://localhost:4000${server.graphqlPath}`);
  console.log(`Subscriptions ready at ws://localhost:4000${server.subscriptionsPath}`);
});

此时你的订阅Resolver就能正常获取到Header:

const resolvers = {
  Subscription: {
    mySubscription: {
      subscribe: (_, args, context) => {
        console.log(context.connection.context.headers); // 现在会输出{ 'X-Auth-Token': 'my-auth-token' }
        // 你的订阅逻辑
      },
    },
  },
};

为什么原方法无效?

client.subscribe中的context是针对单个订阅请求的上下文,而WebSocket是持久连接,自定义Header需要在连接建立的握手阶段传递,而非单个订阅请求时。因此必须通过WebSocketLink的connectionParams配置,才能让Header被服务端获取到。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 06:15:30