Apollo网关对接GraphQL子图时文件上传遇验证错误求助
Apollo网关对接Fastify-Mercurius子图时GraphQL文件上传验证错误解决
问题场景回顾
两个基于Fastify+Mercurius搭建的GraphQL子图A、B,用graphql-upload处理文件上传,通过Apollo网关对接后,普通查询和变更操作都正常,但文件上传始终触发GraphQL验证错误。试过三种处理方式:网关+子图同时处理、仅子图处理、仅网关处理(附代码),都没解决问题。
核心原因分析
Apollo网关默认不会自动处理multipart/form-data类型的请求解析,而graphql-upload要求请求到达GraphQL执行层前完成multipart数据解析。如果网关和子图的处理逻辑不匹配,要么网关解析后的数据子图不认,要么子图等着原始multipart数据但网关已经改了格式,直接导致验证失败。
可行解决方案
方案1:仅在子图侧处理上传(最推荐,亲测有效)
网关不需要做任何multipart解析操作,让它直接转发原始的multipart/form-data请求到子图,由子图自己用graphql-upload处理:
- 子图侧确保配置正确
确认子图的Fastify+Mercurius已经正确集成graphql-upload:import { fastifyGraphQL } from '@mercuriusjs/fastify'; import { GraphQLUpload, processRequest } from 'graphql-upload'; import { makeExecutableSchema } from '@graphql-tools/schema'; // 定义schema,必须声明Upload标量 const typeDefs = ` scalar Upload type Mutation { uploadFile(file: Upload!): Boolean! } `; const resolvers = { Upload: GraphQLUpload, Mutation: { uploadFile: async (_, { file }) => { const { createReadStream, filename } = await file; // 这里写你的文件处理逻辑,比如存到服务器或云存储 return true; } } }; const schema = makeExecutableSchema({ typeDefs, resolvers }); // 注册Mercurius插件前,先添加multipart解析的hook app.addHook('preValidation', async (req, res) => { if (req.headers['content-type']?.includes('multipart/form-data')) { req.body = await processRequest(req.raw, res.raw); } }); app.register(fastifyGraphQL, { schema, graphiql: true // 方便测试 }); - 网关侧无需修改
删掉网关中所有和graphql-upload相关的hook,让Apollo网关直接转发请求到子图即可。
方案2:若必须在网关侧处理(不推荐,复杂度高)
如果网关需要统一处理鉴权、日志等操作,必须解析multipart请求,那要确保解析后的数据能被子图正确识别:
- 网关解析multipart后,不能直接替换
req.body,而是要把文件数据转换成符合Apollo网关转发格式的结构,比如将文件流包装成子图能接收的Promise对象。 - 这种方式需要手动适配网关和子图的数据格式,容易出问题,除非有特殊需求否则不建议用。
排查验证步骤
- 先直接调用子图的GraphQL端点测试文件上传,确认子图本身能正常处理,排除子图自身的问题。
- 查看网关的错误日志,明确验证错误的具体内容——比如是“Upload标量未定义”还是“请求格式不匹配”,针对性修复。
- 确认Apollo网关的组合schema中包含
Upload标量,网关会自动合并子图的schema,如果子图没正确暴露这个标量,会导致网关侧验证失败。
内容的提问来源于stack exchange,提问作者Cyrille keith
相关产品推荐
相关产品推荐

