Apollo联邦网关无法获取req对象转发请求头求助
Apollo Gateway 请求头转发问题
依赖版本
@apollo/gateway: ^2.1.3@apollo/server: ^4.0.0graphql: ^16.6.0
问题描述
无法获取req对象以提取请求头并转发给子图。buildService代码可向下游服务添加请求头,但ApolloServer的context始终为空。尝试了同步/异步方式、用request替代req,甚至直接尝试获取context.req.headers,但均为null。需要实现请求头(如Authorization)的转发。
代码示例
const gateway = new ApolloGateway({ supergraphSdl: new IntrospectAndCompose({ subgraphs: [ { name: "persons", url: process.env.PERSON_SERVER_URL }, ], }), buildService({ url }) { return new RemoteGraphQLDataSource({ url, willSendRequest: ({ request, context }) => { console.log(JSON.stringify(context)); // TRYING TO INJECT AUTH HEADERS HERE } }); } }); const app = express(); const httpServer = http.createServer(app); const server = new ApolloServer({ gateway, context: ({ req }) => { console.log(JSON.stringify(req)); // req IS NULL }, plugins: [ ApolloServerPluginLandingPageDisabled(), ApolloServerPluginDrainHttpServer({ httpServer }) ] }); await server.start(); const graphqlRoute = "/graphql"; app.use( graphqlRoute, bodyParser.json(), expressMiddleware(server), ); await new Promise((resolve) => httpServer.listen(process.env.PORT, "0.0.0.0", resolve)); console.log(`🚀 Server ready at ${JSON.stringify(httpServer.address())}`);
补充说明:我也在Apollo社区提问过,认为联邦模式下应该有简单的配置项来转发Authorization头。
解决方案
核心原因
Apollo Server 4中,expressMiddleware是请求处理的入口,原ApolloServer配置里的context无法直接获取到req对象,必须在expressMiddleware的配置中传递上下文信息。
具体修正步骤
调整上下文传递逻辑
删除ApolloServer配置里的context,转而在expressMiddleware中注入需要的请求信息:const graphqlRoute = "/graphql"; app.use( graphqlRoute, bodyParser.json(), expressMiddleware(server, { // 将需要的请求头传入上下文 context: async ({ req }) => ({ authHeader: req.headers.authorization, // 也可以传入完整headers对象:headers: req.headers }) }), );在willSendRequest中转发请求头
修改buildService中的逻辑,从上下文取出目标头并添加到子图请求中:buildService({ url }) { return new RemoteGraphQLDataSource({ url, willSendRequest: ({ request, context }) => { // 转发Authorization头 if (context.authHeader) { request.http.headers.set('Authorization', context.authHeader); } // 若传入完整headers,可按需转发其他业务头 // if (context.headers['x-user-id']) { // request.http.headers.set('X-User-ID', context.headers['x-user-id']); // } } }); }简化全量转发(按需使用)
如果需要批量转发业务相关请求头,可直接传入整个req对象到上下文,再过滤设置:// expressMiddleware配置 expressMiddleware(server, { context: ({ req }) => ({ req }) }) // willSendRequest逻辑 willSendRequest: ({ request, context }) => { // 定义允许转发的头列表,避免传递host、content-length等无关头 const allowedHeaders = ['authorization', 'x-user-id', 'x-request-id']; allowedHeaders.forEach(header => { const value = context.req.headers[header]; if (value) { request.http.headers.set(header, value); } }); }
内容的提问来源于stack exchange,提问作者Dudo
相关产品推荐
相关产品推荐

