ApolloGateway无法连接GraphQL Express服务问题求助
Apollo Gateway 连接 Product-Service 400 Bad Request 问题排查
问题重现
网关启动代码:
export const server = async () => { const app = express(); const services = [ { name: "product-service", url: "http://localhost:4001/graphql" }]; const availableServices: any[] = []; const gateway = new ApolloGateway({ serviceList: services, buildService: ({ name, url }) => { return new RemoteGraphQLDataSource({ url, }); }, }); const server = new ApolloServer({ subscriptions: false, gateway, }); await server.start(); server.applyMiddleware({ app }); return app.listen(3000); };
Product-Service 启动代码:
export const server = async () => { const schema = await buildSchema({ resolvers: [__dirname + "/api/**/*.resolver.ts"], emitSchemaFile: path.resolve(__dirname, `../schema.gql`), authChecker: authChecker, }); const app = express(); const server = new ApolloServer({ schema, context: (ctx: Context) => { const context = ctx; return context; }, }); await server.start(); server.applyMiddleware({ app, }); return app.listen(4001); };
报错信息:
Error checking for changes to service definitions: Couldn't load service definitions for "product-service" at http://localhost:4001/graphql: 400: Bad Request
排查步骤
1. 确认子服务是否开启 Introspection 接口
Apollo Gateway 依赖 GraphQL 的 introspection 查询获取子服务 Schema,若子服务禁用该功能会直接返回 400 错误:
- 在 Product-Service 的 ApolloServer 配置中显式开启 introspection(开发环境默认开启,但生产环境或手动配置可能关闭):
const server = new ApolloServer({ schema, context: (ctx: Context) => { const context = ctx; return context; }, introspection: true // 强制开启 introspection });
2. 验证子服务端点可用性
直接访问 http://localhost:4001/graphql,在 GraphQL Playground 执行以下 introspection 查询,确认能否正常返回 Schema:
query IntrospectionQuery { __schema { queryType { name } types { name } } }
- 若查询失败,检查 Product-Service 启动日志,确认 Schema 生成是否存在错误(如 resolver 路径配置错误、类型定义冲突)。
3. 排查认证中间件拦截问题
你的 Product-Service 配置了 authChecker,若该中间件强制要求所有请求携带认证信息,会拦截网关的 introspection 请求:
- 修改
authChecker,允许 introspection 查询跳过认证:export const authChecker: AuthChecker<Context> = ({ context }, roles) => { // 识别 introspection 查询并跳过认证 const isIntrospection = context.req.body?.query?.startsWith('query IntrospectionQuery'); if (isIntrospection) return true; // 原有认证逻辑 return !!context.req.user; };
4. 检查版本兼容性
不同版本的 Apollo Gateway 与 Apollo Server 可能存在兼容性问题,导致 Schema 请求格式不匹配:
- 确认
@apollo/gateway、apollo-server、apollo-server-express为同一大版本系列,避免跨版本调用的格式冲突。
5. 增加请求日志定位细节
在网关的 buildService 中添加日志,查看请求/响应详情:
buildService: ({ name, url }) => { return new RemoteGraphQLDataSource({ url, willSendRequest({ request }) { console.log(`网关请求 ${url}:`, request); }, didReceiveResponse({ response, request }) { console.log(`网关收到响应 ${url}:`, response); }, }); },
通过日志确认网关发送的查询内容,以及子服务返回的具体错误信息,进一步缩小问题范围。
内容的提问来源于stack exchange,提问作者Furkan Gulsen
相关产品推荐
相关产品推荐

