配置Node.js Apollo Server的Context时如何识别当前请求的mutation
Apollo Server 按Mutation动态配置Context的高效实现方案
最优方案:复用Apollo内置解析能力(无重复解析开销)
不需要自行解析请求体的Query,直接通过Apollo的插件钩子拿到已经解析完成的操作信息,完全避免重复解析,也不需要处理嵌套的AST结构,实现逻辑如下:
- 初始化Context时预留存储操作信息的字段
- 通过
didResolveOperation插件钩子获取Apollo解析完成的操作结果,直接修改当前请求的Context即可
代码示例(Apollo Server 4):
import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; const server = new ApolloServer({ typeDefs, resolvers, // 初始化基础Context context: async ({ req }) => { return { req, currentOperation: null, // 其他通用Context字段 }; }, plugins: [ { async requestDidStart() { return { // 该钩子在Apollo完成Query解析、确定操作类型后触发 async didResolveOperation(requestContext) { const { operation, contextValue } = requestContext; // 直接获取结构化的操作信息,无需自行处理AST const operationType = operation.operation; // 返回 query / mutation / subscription const operationName = operation.selectionSet.selections[0].name.value; // 写入Context contextValue.currentOperation = { type: operationType, name: operationName }; // 在这里添加你的条件逻辑 if (operationType === 'mutation' && operationName === 'createUser') { // 比如给特定Mutation跳过权限校验 contextValue.skipAuth = true; } } }; } } ] });
该方案是性能最优的实现,完全复用Apollo本身的解析结果,没有额外开销,支持所有复杂Query场景,适配Apollo Server 3/4所有版本。
轻量场景可选方案
方案1:Resolver直接取Info字段
如果不需要在全局Context初始化阶段使用Mutation信息,仅单个Resolver需要判断,直接取Resolver的第四个参数info即可,无需额外配置:
const resolvers = { Mutation: { updateUser: async (parent, args, context, info) => { const isMutation = info.operation.operation === 'mutation'; const mutationName = info.operation.name?.value; // 你的业务逻辑 } } };
方案2:正则快速匹配(简单场景)
如果业务场景的Query结构简单,没有多操作、别名、注释等复杂情况,可以用正则快速匹配Mutation名称,性能损耗几乎可以忽略:
context: async ({ req }) => { const query = req.body.query || ''; // 匹配Mutation后的第一个操作名 const mutationMatch = query.match(/mutation\s+(\w+)/); const currentMutation = mutationMatch ? mutationMatch[1] : null; return { currentMutation, // 其他逻辑 }; }
该方案仅适合简单业务场景,复杂Query可能出现匹配误差。
内容的提问来源于stack exchange,提问作者Sihoon Kim
相关产品推荐
相关产品推荐

