NestJS GraphQL订阅:如何获取上下文并向解析器/拦截器传参?
解决NestJS订阅拦截器获取上下文及用户信息的问题
针对graphql-ws方案
在onConnect中处理授权并传递用户信息
在订阅配置的onConnect回调里,解析授权头获取用户后,需要返回用户对象,这个对象会自动注入到GraphQL的执行上下文中:subscriptions: { 'graphql-ws': { path: '/apis/event-service/graphql', onConnect: async (ctx) => { // 从连接参数中获取授权头 const authHeader = ctx.connectionParams?.Authorization || ctx.connectionParams?.authorization; if (!authHeader) { throw new Error('未授权'); } // 示例:解析token获取用户 const user = await verifyToken(authHeader.split(' ')[1]); // 返回用户,会被挂载到GraphQL上下文 return { user }; }, }, }拦截器中获取上下文和用户
在拦截器的intercept方法里,通过GqlExecutionContext直接获取上下文,此时上下文已包含onConnect返回的用户:intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const gqlCtx = GqlExecutionContext.create(context); // 获取graphql-ws传递的上下文 const { user } = gqlCtx.getContext(); // 将用户挂载到解析器可访问的位置(比如上下文的req对象) gqlCtx.getContext().req.user = user; return next.handle(); }
针对subscriptions-transport-ws方案
在onConnect中处理授权并挂载用户到连接上下文
该库的连接上下文需要挂载到connection.context上,后续才能在拦截器中获取:subscriptions: { 'subscriptions-transport-ws': { path: '/apis/event-service/graphql', onConnect: async (connectionParams, webSocket, context) => { const authHeader = connectionParams.Authorization || connectionParams.authorization; if (!authHeader) { throw new Error('未授权'); } const user = await verifyToken(authHeader.split(' ')[1]); // 将用户挂载到连接上下文 context.connection.context.user = user; return context.connection.context; }, }, }拦截器中获取上下文和用户
需要通过switchToWs().getClient()获取连接客户端,再从其context属性中拿到用户:intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const gqlCtx = GqlExecutionContext.create(context); // 获取subscriptions-transport-ws的客户端连接上下文 const wsClient = gqlCtx.switchToWs().getClient(); const { user } = wsClient.context; // 将用户挂载到解析器可访问的位置 gqlCtx.getContext().req.user = user; return next.handle(); }
关键注意点
- 两种库的上下文传递机制完全不同,必须对应正确的获取方式,否则会返回
undefined。 - 拦截器需确保是全局拦截器,或被正确应用到订阅解析器所在的模块/解析器上。
- 在
onConnect中必须完成用户信息的解析和挂载/返回,否则后续拦截器无法获取到用户数据。
内容的提问来源于stack exchange,提问作者SebastianG
相关产品推荐
相关产品推荐

