如何在Apollo Client中同时实现认证与GraphQL订阅功能?
解决Apollo Client + React Native中GraphQL订阅与认证整合的类型错误及异步token问题
问题根源
你遇到的类型错误是因为混用了旧版apollo-link包和@apollo/client内置的ApolloLink。Apollo Client v3+已将所有链接相关功能整合到@apollo/client中,无需单独安装apollo-link,这会导致类型不兼容。另外,AsyncStorage.getItem是异步方法,同步获取会拿到Promise而非实际token,同时WebSocket连接的认证参数也需要动态获取token。
完整解决方案代码
import { ApolloClient, split, HttpLink, InMemoryCache, ApolloLink, concat } from '@apollo/client'; import { getMainDefinition } from '@apollo/client/utilities'; import { GraphQLWsLink } from "@apollo/client/link/subscriptions"; import { createClient } from "graphql-ws"; import AsyncStorage from '@react-native-async-storage/async-storage'; // 1. 配置WebSocket链接,动态获取认证token const wsLink = new GraphQLWsLink( createClient({ url: "ws://localhost:4000/subscriptions", // 异步获取token,支持重连时更新token connectionParams: async () => { const token = await AsyncStorage.getItem('token'); return { authToken: token ? `Bearer ${token}` : "", }; }, }), ); // 2. 配置HTTP链接 const httpLink = new HttpLink({ uri: 'http://localhost:4000/graphql' }); // 3. 异步认证中间件(处理HTTP请求的header) const authLink = new ApolloLink(async (operation, forward) => { const token = await AsyncStorage.getItem('token'); operation.setContext({ headers: { authorization: token ? `Bearer ${token}` : "", }, }); return forward(operation); }); // 4. 拼接HTTP链接与认证中间件 const authenticatedHttpLink = concat(authLink, httpLink); // 5. 拆分链接:订阅用WebSocket,其他用带认证的HTTP const splitLink = split( ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' ); }, wsLink, authenticatedHttpLink, ); // 6. 创建Apollo Client实例 export const client = new ApolloClient({ cache: new InMemoryCache(), link: splitLink, });
关键修复点说明
- 统一依赖导入:所有
ApolloLink、concat等均从@apollo/client导入,删除对apollo-link包的依赖,彻底解决类型不兼容问题。 - 异步token处理:
- HTTP认证中间件使用
async/await获取token,ApolloLink支持异步操作,会等待Promise完成后再转发请求。 - WebSocket的
connectionParams配置为异步函数,每次建立连接(包括重连)时都会重新获取最新token,避免token过期后连接失效。
- HTTP认证中间件使用
- 正确的链接拼接顺序:先将认证中间件与HTTP链接拼接,再通过
split函数区分订阅和普通请求的链接,确保HTTP请求都携带认证头,订阅请求通过WebSocket传递认证参数。
额外注意事项
- 确保已安装所有必要依赖:
@apollo/client、graphql-ws、@react-native-async-storage/async-storage,无需安装apollo-link。 - 如果token可能在应用运行中更新(比如用户登录/登出),可以考虑监听token变化,调用
wsLink.client.reconnect()触发重新获取token。
内容的提问来源于stack exchange,提问作者pelotador.1
相关产品推荐
相关产品推荐

