首页 > 解决方案 > 为什么当我使用 apollo-server 上传文件时,文件已上传但文件为 0kb?

问题描述

我试图解决这个问题,但我不明白为什么文件被上传但他的大小是 0Kb。我在教程中看到了这段代码,但他在那个教程上工作,但对我不起作用

const { ApolloServer, gql } = require('apollo-server');
const path = require('path');
const fs = require('fs');

const typeDefs = gql`
  type File {
    url: String!
  }

  type Query {
    hello: String!
  }

  type Mutation {
    fileUpload(file: Upload!): File!
  }
`;

const resolvers = {
  Query: {
    hello: () => 'Hello world!',
  },
  Mutation: {
    fileUpload: async (_, { file }) => {
      const { createReadStream, filename, mimetype, encoding } = await file;
      const stream = createReadStream();
      const pathName = path.join(__dirname, `/public/images/${filename}`);
      await stream.pipe(fs.createWriteStream(pathName));

      return {
        url: `http://localhost:4000/images/${filename}`,
      };
    },
  },
};

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

server.listen().then(({ url }) => {
  console.log(` Server ready at ${url}`);
});

然后当我上传文件时,它被上传了,但是文件是0kb


像这样

标签: file-uploadgraphqlapolloapollo-serverapollostack

解决方案


发生的情况是解析器在文件上传之前返回,导致服务器在客户端完成上传之前做出响应。您需要在解析器中承诺并等待文件上传流事件。

这是一个例子:

https://github.com/jaydenseric/apollo-upload-examples/blob/c456f86b58ead10ea45137628f0a98951f63e239/api/server.js#L40-L41

在你的情况下:

const resolvers = {
  Query: {
    hello: () => "Hello world!",
  },
  Mutation: {
    fileUpload: async (_, { file }) => {
      const { createReadStream, filename } = await file;
      const stream = createReadStream();
      const path = path.join(__dirname, `/public/images/${filename}`);

      // Store the file in the filesystem.
      await new Promise((resolve, reject) => {
        // Create a stream to which the upload will be written.
        const writeStream = createWriteStream(path);

        // When the upload is fully written, resolve the promise.
        writeStream.on("finish", resolve);

        // If there's an error writing the file, remove the partially written
        // file and reject the promise.
        writeStream.on("error", (error) => {
          unlink(path, () => {
            reject(error);
          });
        });

        // In Node.js <= v13, errors are not automatically propagated between
        // piped streams. If there is an error receiving the upload, destroy the
        // write stream with the corresponding error.
        stream.on("error", (error) => writeStream.destroy(error));

        // Pipe the upload into the write stream.
        stream.pipe(writeStream);
      });

      return {
        url: `http://localhost:4000/images/${filename}`,
      };
    },
  },
};

请注意,使用这样的文件名来存储上传的文件可能不是一个好主意,因为将来使用相同文件名的上传将覆盖之前的文件。我不确定如果两个客户端同时上传两个同名文件会发生什么。


推荐阅读