Apollo Context为空问题求助:Angular客户端传参后服务端获取不到
我之前也碰到过一模一样的情况,客户端明明传了Context,但服务端就是拿不到,大概率是服务端的Context配置环节没跟上,或者链路里丢了Context,咱们一步步来排查:
1. 检查服务端Apollo Server的Context配置
这是最常见的原因——Apollo Server不会自动把客户端传来的Context直接注入到Resolver的参数里,你需要手动在创建ApolloServer时配置context函数,把客户端的Context提取出来并返回:
举个Apollo Server v3+的示例:
const { ApolloServer } = require('@apollo/server'); const { expressMiddleware } = require('@apollo/server/express4'); const server = new ApolloServer({ typeDefs, resolvers: { Query: { message: { type: GraphQLString, resolve: (obj, args, context, info) => { console.log('context: ', context); // 现在应该能拿到{ test: 'test' }了 return 'hey'; } } } }, // 关键:配置context函数,提取客户端传来的Context context: async ({ req, res, operation }) => { // 从operation中获取客户端传递的Context const clientContext = operation.getContext(); // 返回的对象会作为Resolver的context参数 return { ...clientContext }; } }); // 后续的express中间件配置...
如果是Apollo Server v2,context函数的参数略有不同,你可以从req的body里找extensions(客户端的Context会被放在这里):
context: ({ req }) => { const clientContext = req.body?.extensions?.context || {}; return clientContext; }
2. 排查Angular Apollo Client的链路配置
如果你在Angular里用了自定义的Apollo Link(比如apollo-link-context、认证链路等),要确保这些链路没有拦截或丢失Context:
比如自定义链路要正确传递operation对象,不要修改后忘记传递:
import { ApolloLink } from '@apollo/client/core'; const customLink = new ApolloLink((operation, forward) => { // 如果你需要修改Context,比如添加认证信息,要确保操作后传递原operation const modifiedContext = { ...operation.getContext(), authToken: 'xxx' }; operation.setContext(modifiedContext); // 必须返回forward(operation),否则链路会中断,Context也传不下去 return forward(operation); }); // 把自定义链路加入ApolloClient的link链中 const apolloClient = new ApolloClient({ link: customLink.concat(httpLink), cache: new InMemoryCache(), });
3. 版本兼容性检查
如果你的Apollo Client和Apollo Server版本差距较大,也可能出现Context传递的问题。比如Apollo Client v3和Apollo Server v2的Context传递方式有差异,建议尽量保持两者版本在同一大版本范围内(比如都用v3或都用v4)。
快速验证方法
你可以在客户端的链路里添加一个日志链路,确认Context是否真的发出去了:
const logLink = new ApolloLink((operation, forward) => { console.log('客户端发送的Context:', operation.getContext()); return forward(operation); }); // 把logLink放在链路最前面 const apolloClient = new ApolloClient({ link: logLink.concat(httpLink), cache: new InMemoryCache(), });
如果这里能看到{ test: 'test' },那问题肯定在服务端的配置上;如果看不到,那就是客户端的Context没被正确设置。
内容的提问来源于stack exchange,提问作者Taieb

