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
相关产品推荐
相关产品推荐

