Node.js下Apollo GraphQL如何动态切换introspection无需重启服务
Apollo GraphQL 动态切换introspection无重启实现方案
你不需要用静态初始化配置、也不需要用粗暴的请求体过滤中间件,直接用Apollo Server原生插件机制配合运行时配置就能实现,完全满足热切换、无侵入的要求。
实现思路
- 跳过Apollo Server初始化阶段的静态
introspection配置项,这个配置是实例级别的,修改后必须重启才会生效,不适合热切换场景。 - 基于Apollo原生插件的
didResolveOperation生命周期做判断:这个钩子会在每次请求完成GraphQL语法解析、生成AST之后,正式执行查询逻辑之前触发,属于框架官方支持的扩展点,比外层挂中间件的耦合度低很多,也不会出现字符串匹配的误判问题。 - 把introspection开关状态存储在可动态修改的运行时配置源里,最简单的可以用内存变量,复杂场景可以对接Redis、数据库配置表、配置中心,切换开关时直接修改配置值即可,无需重启服务。
核心实现代码
首先定义可热更新的运行时配置,你可以根据自己的需求替换成其他配置存储方式:
// 运行时配置,可通过带权限的管理接口、配置中心推送等方式随时修改值 const appRuntimeConfig = { graphqlIntrospectionEnabled: false }
实现动态introspection控制插件:
const dynamicIntrospectionPlugin = { async requestDidStart() { return { async didResolveOperation(ctx) { // 基于解析后的AST判断当前请求是否为introspection查询 const containIntrospectionField = ctx.operation.selectionSet.selections.some( selection => selection.kind === 'Field' && ['__schema', '__type'].includes(selection.name.value) ) if (containIntrospectionField && !appRuntimeConfig.graphqlIntrospectionEnabled) { throw new Error('Introspection is disabled for current environment') } } } } }
初始化Apollo Server时注册插件即可,不需要额外配置静态introspection参数:
const apolloServer = new ApolloServer({ typeDefs, resolvers, plugins: [dynamicIntrospectionPlugin] })
方案优势
- 无重启热切换:开关状态修改后对所有新请求即时生效,不需要重启Node.js进程
- 准确率高:基于GraphQL解析后的AST判断,不会出现中间件正则匹配请求体导致的误杀(比如业务查询的注释、字符串参数里包含
__schema关键字不会被错误拦截) - 扩展性强:你可以很方便的叠加细粒度控制逻辑,比如只对内部IP、携带管理员鉴权token的请求开放introspection,不需要全局统一开关
- 原生兼容:插件是Apollo官方支持的扩展方式,和现有所有Apollo生态的插件、功能没有兼容问题
注意:不建议使用直接匹配请求原文的中间件方案,除了误判问题外,这类中间件无法处理GraphQL请求的别名、片段嵌套等场景,存在被绕过的风险。
内容的提问来源于stack exchange,提问作者user18668497
相关产品推荐
相关产品推荐

