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

NextJS+NextAuth+Cognito+Hasura环境Apollo订阅问题求助

问题:Next.js + Hasura + Apollo Client 使用graphql-ws实现订阅失败

我基于Hasura/GraphQL启动新项目,有NextJS使用经验,已完成Cognito集成,登录、自定义声明、JWT验证均正常,部分调用Hasura的Next页面可正常工作。但通过Apollo使用订阅时报错:
Error: subscriptions are not supported over HTTP, use websockets instead

现有教程文档未适配当前库:Hasura文档仍使用已废弃的subscriptions-transport-ws,而当前需用graphql-ws替代,导致依赖兼容问题。


已实现的正常运行代码

Apollo Client 配置(lib/apolloClient.js)

import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import { getSession } from "next-auth/react";

const httpLink = createHttpLink({
  uri: "<HASURA_URL_HERE>",
});

const authLink = setContext(async (_, { headers }) => {
  const session = await getSession();
  const token = session?.idToken;

  const h = {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : ""
    },
  };
  console.log("headers", h, session);
  return h;
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

export default client;

_app.js 配置

import "@/styles/globals.css";
import { SessionProvider, useSession } from "next-auth/react";
import { ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import { CacheProvider } from "@emotion/react";
import theme from "../theme";
import createEmotionCache from "../theme/createEmotionCache";
import Head from "next/head";
import HeaderBar from "@/components/HeaderBar";
import { ApolloProvider } from "@apollo/client";
import client from "../lib/apolloClient";

// Client-side cache, shared for the whole session of the user in the browser.
const clientSideEmotionCache = createEmotionCache();

export default function App({
  Component,
  pageProps: { session, ...pageProps },
}) {
  return (
    <CacheProvider value={clientSideEmotionCache}>
      <Head>
        <meta name="viewport" content="initial-scale=1, width=device-width" />
      </Head>
      <ThemeProvider theme={theme}>
        <SessionProvider session={session}>
          <ApolloProvider client={client}>
            <CssBaseline />
            <HeaderBar />
            {Component.auth ? (
              <Auth>
                <Component {...pageProps} />
              </Auth>
            ) : (
              <Component {...pageProps} />
            )}
          </ApolloProvider>
        </SessionProvider>
      </ThemeProvider>
    </CacheProvider>
  );
}

function Auth({ children }) {
  // if `{ required: true }` is supplied, `status` can only be "loading" or "authenticated"
  const { status } = useSession({ required: true });

  if (status === "loading") {
    return <div>Loading...</div>;
  }

  return children;
}

示例查询页面(pages/event.js)

import EventsRow from "@/components/Events/EventsRow";
import EventsRowHeader from "@/components/Events/EventsRowHeader";
import { useQuery, gql } from "@apollo/client";

const GET_EVENTS_QUERY = gql`
  query GetEvents {
    events {
      id
      name
      eventDate
    }
  }
`;

export default function Events() {
  const { loading, error, data } = useQuery(GET_EVENTS_QUERY);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  const events = data.events;

  return (
    <div>
      <EventsRowHeader />
      {events.map((e) => (
        <EventsRow key={e.id} event={e} />
      ))}
    </div>
  );
}

注:查询功能正常,返回用户有权限查看的2条事件数据(数据库共5条),JWT与Hasura权限配置无误。


尝试过的方案(未成功)

尝试拆分Apollo Client链接区分查询与订阅,但新旧库无法兼容:

const link = split(
  ({ query }) => {
    const definition = getMainDefinition(query);
    return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
  },
  wsLink,
  httpLink,
);

请求需求

这是常见使用场景,求适配当前graphql-ws库的完整示例,也愿意参与开源项目共建相关样板代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:44:55