You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apollo Server GraphQL 文件上传异常:响应无限缓冲且文件为空

解决Apollo Server 2.0文件上传无限缓冲&空文件问题

既然你已经定位到问题出在mutation和schema文件里,那咱们重点排查这两块的常见错误,帮你解决响应无限缓冲和生成空文件的问题:

一、Schema 文件的常见问题

  1. 未正确定义Upload标量
    Apollo Server 2.x不会自动包含Upload标量,你需要显式在schema中声明,并且在resolver中绑定对应的实现:

    # 必须添加这个标量定义
    scalar Upload
    
    type Mutation {
      # 参数类型必须是Upload!,确保文件是必填的
      uploadFile(file: Upload!): String!
    }
    
  2. Mutation字段参数类型错误
    如果你把file的类型写成了String或者其他非Upload类型,会导致无法正确接收文件流,直接引发后续的写入错误。

二、Mutation Resolver 的关键错误点

这部分是空文件和无限缓冲的重灾区,主要是对Upload类型的异步处理不到位:

  1. 没有await Upload对象
    Upload类型本质是一个Promise,直接使用file而不await它,会导致你拿到的不是包含文件流的对象,而是一个未解析的Promise,自然读不到任何数据。

  2. 未等待文件流写入完成
    如果你只是调用stream.pipe(writeStream)就直接返回响应,Node.js的流是异步的,此时文件还没写完就结束请求,会导致生成空文件,同时服务器可能因为未处理完流操作而陷入缓冲状态。

  3. 缺少错误捕获机制
    流操作过程中如果出现错误(比如权限不足、磁盘空间不够),没有捕获的话会导致服务器挂起,出现无限缓冲的情况。

正确的Resolver示例

const { createWriteStream } = require('fs');
const { join } = require('path');
const { GraphQLUpload } = require('graphql-upload');

const resolvers = {
  // 必须绑定Upload标量的实现
  Upload: GraphQLUpload,
  Mutation: {
    async uploadFile(_, { file }) {
      try {
        // 必须await file来获取文件的实际数据
        const { createReadStream, filename, mimetype } = await file;
        const stream = createReadStream();
        
        // 确保images文件夹存在(可以提前手动创建,或者用fs.mkdirSync判断)
        const filePath = join(__dirname, 'images', filename);
        
        // 用Promise包裹流操作,等待写入完成
        await new Promise((resolve, reject) => {
          const writeStream = createWriteStream(filePath);
          stream.pipe(writeStream);
          
          // 监听完成和错误事件
          writeStream.on('finish', () => resolve(`File saved: ${filename}`));
          writeStream.on('error', (err) => {
            console.error('File write error:', err);
            reject(new Error('Failed to save file'));
          });
        });
        
        return `File uploaded successfully: ${filename}`;
      } catch (err) {
        console.error('Upload error:', err);
        throw new Error('Upload failed. Please try again.');
      }
    }
  }
};

三、额外的配置检查

除了schema和resolver,还要确保Apollo Server启用了文件上传中间件:

const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const { graphqlUploadExpress } = require('graphql-upload');

const app = express();
// 添加文件上传中间件,设置最大文件大小等限制
app.use(graphqlUploadExpress({ maxFileSize: 10 * 1024 * 1024, maxFiles: 1 }));

const server = new ApolloServer({ typeDefs, resolvers });
server.applyMiddleware({ app });

app.listen(4000, () => console.log('Server running on http://localhost:4000/graphql'));

总结

你的问题大概率是因为没有await Upload对象,或者没有等待文件流写入完成就返回响应,导致服务器无法正确结束请求(无限缓冲),同时文件没有被完整写入(空文件)。按照上面的示例调整schema和resolver,应该就能解决问题了。

内容的提问来源于stack exchange,提问作者user14645831

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 21:42:58