如何将文件作为GraphQL mutation变量传递?graphql-upload报Upload值无效错误
问题原因&解决方案
你碰到的错误核心有三个问题:
- 前端发送请求时用了
application/json格式序列化body,File对象无法被JSON序列化,所以传到服务端变成了空对象{} - 服务端resolver里的mutation名和Schema定义不匹配
- ApolloServer默认会自带上传处理逻辑,和你引入的
graphql-upload冲突,需要手动关闭
第一步:修改前端graphQLFetch函数,适配文件上传
你需要判断请求里有没有File类型的变量,如果有就用FormData格式提交,不要用JSON:
async function graphQLFetch(query, variables = {}) { // 检查变量里是否有File对象 const hasFile = Object.values(variables).some(val => val instanceof File) if (hasFile) { const formData = new FormData() formData.append('query', query) formData.append('variables', JSON.stringify(variables, (key, value) => { // 把File对象单独提出来,JSON序列化时留占位符 if (value instanceof File) { return null } return value })) // 把File对象追加到formData里 Object.entries(variables).forEach(([key, value]) => { if (value instanceof File) { formData.append(key, value) } }) const response = await fetch('/graphql', { method: 'POST', // 不要手动设置Content-Type,浏览器会自动带上multipart/form-data和边界值 body: formData }) const result = await response.json() return result.data } else { // 普通请求走原来的逻辑 const response = await fetch('/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query, variables }) }) const result = await response.json() return result.data } }
第二步:修正服务端配置
1. 修正resolver里的mutation名
你Schema里定义的mutation是addThumbnailTest,但resolver里写的是handleThumbnailChange,要对应上:
const resolvers = { Upload: GraphQLUpload, Mutation: { // 这里改名和Schema一致 addThumbnailTest: async (_, { thumbnailFile }) => { // 处理上传的文件,比如读取、存到服务器/云存储 const { createReadStream, filename, mimetype } = await thumbnailFile // 你自己的业务逻辑,返回对应的thumbnailSrc即可 return `/uploads/${filename}` } } }
2. 关闭ApolloServer默认的上传处理,避免和graphql-upload冲突
初始化ApolloServer时加上uploads: false配置:
const server = new ApolloServer({ typeDefs: fs.readFileSync(path.join(__dirname, 'schema.graphql'), 'utf-8'), resolvers, // 关闭默认上传逻辑,用你引入的graphql-upload处理 uploads: false });
第三步:检查中间件加载顺序
确保graphqlUploadExpress()中间件加载在Apollo中间件之前,你现在的写法是对的,不用改。
修改完之后重新启动服务端测试,就能正常拿到上传的文件了。
内容的提问来源于stack exchange,提问作者tiller1010
相关产品推荐
相关产品推荐

