如何为所有GraphQL请求的请求头注入Id(示例:Id:1234)
在Apollo GraphQL中全局注入请求头Id的实现方案
刚好之前做过类似的需求,给你整理几个不同场景下的可行方案,都是经过实践验证的:
Web端(React/Vue等基于Apollo Client的项目)
Apollo Client的核心是通过Link机制来拦截并修改请求,这是全局注入请求头最直接的方式。
基础实现(固定或可获取的Id)
先创建一个自定义Link,在每个请求发送前注入Id头:
import { ApolloClient, InMemoryCache, createHttpLink, ApolloLink } from '@apollo/client'; // 1. 创建基础的HTTP链接 const httpLink = createHttpLink({ uri: '你的GraphQL服务端点URL', }); // 2. 自定义拦截Link,注入请求头 const idInjectLink = new ApolloLink((operation, forward) => { // 这里替换成你实际获取Id的逻辑:比如从localStorage、全局状态或接口返回 const targetId = '1234'; // 修改请求上下文,添加Id头 operation.setContext(({ headers = {} }) => ({ headers: { ...headers, // 保留原有请求头 Id: targetId, }, })); // 继续执行请求链 return forward(operation); }); // 3. 组合Link并创建Apollo Client const client = new ApolloClient({ link: idInjectLink.concat(httpLink), // 先执行自定义Link,再走HTTP请求 cache: new InMemoryCache(), });
动态更新Id的场景
如果Id是动态变化的(比如用户登录后才生成),可以用一个全局可修改的变量存储Id,配合更新函数:
// 全局存储当前Id,初始值可设为默认值或空 let currentUserId = ''; // 提供更新Id的方法,比如用户登录后调用 export const updateRequestId = (newId) => { currentUserId = newId; }; // 自定义Link逻辑调整为读取全局变量 const idInjectLink = new ApolloLink((operation, forward) => { operation.setContext(({ headers = {} }) => ({ headers: { ...headers, Id: currentUserId || '默认兜底Id', }, })); return forward(operation); });
服务端渲染(SSR)场景(比如Next.js)
在SSR环境下,Id可能需要从请求的Cookie或Header中获取,要在服务端初始化Apollo Client时注入:
import { ApolloProvider, ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; import { setContext } from '@apollo/client/link/context'; function MyApp({ Component, pageProps, apolloClient }) { return ( <ApolloProvider client={apolloClient}> <Component {...pageProps} /> </ApolloProvider> ); } MyApp.getInitialProps = async ({ ctx }) => { // 从服务端请求的Cookie中获取Id(根据你的存储方式调整) const serverSideId = ctx.req?.cookies?.userId; const httpLink = createHttpLink({ uri: '你的GraphQL服务端点URL', }); const authLink = setContext((_, { headers }) => ({ headers: { ...headers, Id: serverSideId || '默认Id', }, })); const apolloClient = new ApolloClient({ ssrMode: true, link: authLink.concat(httpLink), cache: new InMemoryCache(), }); return { apolloClient }; }; export default MyApp;
移动端场景
Android(Apollo Android)
通过添加自定义Interceptor来拦截请求并注入头:
import com.apollographql.apollo3.ApolloClient import com.apollographql.apollo3.interceptor.ApolloInterceptor import com.apollographql.apollo3.api.ApolloRequest import com.apollographql.apollo3.api.ApolloResponse import kotlinx.coroutines.flow.Flow val apolloClient = ApolloClient.builder() .serverUrl("你的GraphQL服务端点URL") .addInterceptor(object : ApolloInterceptor { override fun intercept( request: ApolloRequest<*>, chain: ApolloInterceptorChain ): Flow<ApolloResponse<*>> { // 修改请求,添加Id头(从SharedPreferences或其他存储获取) val modifiedRequest = request.newBuilder() .addHeader("Id", "1234") .build() return chain.proceed(modifiedRequest) } }) .build()
iOS(Apollo iOS)
通过自定义Interceptor插入到请求链中:
import Apollo // 1. 创建自定义拦截器 class IdHeaderInterceptor: ApolloInterceptor { func interceptAsync<Operation: GraphQLOperation>( chain: RequestChain, request: HTTPRequest<Operation>, response: HTTPResponse<Operation>?, completion: @escaping (Result<GraphQLResult<Operation.Data>, Error>) -> Void ) { // 注入Id头(从UserDefaults或其他存储获取) request.addHeader(name: "Id", value: "1234") // 继续执行请求链 chain.proceedAsync(request: request, response: response, completion: completion) } } // 2. 初始化Apollo Client时添加拦截器 let endpointURL = URL(string: "你的GraphQL服务端点URL")! let networkTransport = RequestChainNetworkTransport( interceptorProvider: DefaultInterceptorProvider(client: ApolloClient()), endpointURL: endpointURL ) // 将自定义拦截器插入到请求链最前面 networkTransport.interceptors.insert(IdHeaderInterceptor(), at: 0) let apolloClient = ApolloClient(networkTransport: networkTransport)
注意事项
- 如果Id是敏感信息,避免用localStorage这类易被XSS攻击的存储方式,优先考虑HttpOnly Cookie或安全的状态管理方案。
- 若某些请求不需要注入Id,可以在自定义Link/Interceptor中添加判断逻辑(比如根据
operation.operationName过滤)。 - 确保后端服务已经配置允许接收
Id请求头(避免CORS问题)。
内容的提问来源于stack exchange,提问作者coder94
相关产品推荐
相关产品推荐

