上传的图像中不存在createReadStream。

3

我正在使用node v14.17.0,“apollo-server-express”:“^2.25.0”,“graphql-upload”:“^12.0.0”

我试图上传一张图片,但是我无法从从graphiql上传的图片中获取 createReadStream。 我正在使用Altair graphiql

这是我的index.js

const app = express();

app.use(
  graphqlUploadExpress({
    maxFileSize: 30000000,
    maxFiles: 20,
  })
);

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: contextMiddleware,
  uploads: false,
});


server.applyMiddleware({ app });

app.listen(PORT, () => {
  console.log("Success");
});

在我的 typedefs 中,我已经提到了。
 gql`
      scalar Upload

我的解析器有

Upload: GraphQLUpload,

我尝试跟进这个问题 apollographql/apollo-server#3508,但似乎对我无效。将版本降级至nodev12也没有帮助。

我上传的图片包含以下内容

{"filename":"download123.jpg","mimetype":"image/jpeg","encoding":"7bit"}
3个回答

1
下面是一个使用graphql-uploadapollo-server-express包的单文件上传示例。
包版本:
"apollo-server-express": "^2.15.1",
"graphql-upload": "^12.0.0",
"graphql": "^14.6.0",

Nodejs版本:v14.16.0

GraphQL服务器:

import { ApolloServer, gql } from 'apollo-server-express';
import express from 'express';
import path from 'path';
import { createWriteStream, unlink } from 'fs';
import { graphqlUploadExpress } from 'graphql-upload';

const app = express();
const PORT = 3000;
const UPLOAD_DIR = path.resolve(__dirname, './uploads');

const typeDefs = gql`
  scalar Upload
  type Query {
    dummy: String
  }
  type Mutation {
    upload(upload: Upload!): Boolean
  }
`;

const resolvers = {
  Query: {},
  Mutation: {
    async upload(_, { upload }) {
      const { file } = upload;
      const { filename, mimetype, createReadStream } = await file;
      const stream = createReadStream();
      const id = Date.now();
      const uploadPath = `${UPLOAD_DIR}/${id}-${filename}`;
      console.log(filename, mimetype, createReadStream, stream);

      await new Promise((resolve, reject) => {
        const writeStream = createWriteStream(uploadPath);
        writeStream.on('finish', resolve);
        writeStream.on('error', (error) => {
          unlink(uploadPath, () => {
            reject(error);
          });
        });
        stream.on('error', (error) => writeStream.destroy(error));
        stream.pipe(writeStream);
      });

      return true;
    },
  },
};

app.use(
  graphqlUploadExpress({
    maxFileSize: 30000000,
    maxFiles: 20,
  }),
);

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

server.applyMiddleware({ app });

app.listen(PORT, () => console.log(`GraphQL server is listening on http://localhost:${PORT}/graphql`));

使用Altair GraphQL向客户端发送GraphQL请求。

enter image description here

服务器端的日志,成功获取createReadStream
GraphQL server is listening on http://localhost:3000/graphql
matej-sefcik-GCRbVZydPT4-unsplash.jpg image/jpeg [Function: createReadStream] <ref *1> ReadStream {
  _readableState: ReadableState {
    objectMode: false,
    highWaterMark: 16384,
    buffer: BufferList { head: null, tail: null, length: 0 },
    length: 0,
    pipes: [],
    flowing: null,
    ended: false,
    endEmitted: false,
    reading: false,
    sync: true,
    needReadable: false,
    emittedReadable: false,
    readableListening: false,
    resumeScheduled: false,
    errorEmitted: false,
    emitClose: true,
    autoDestroy: true,
    destroyed: false,
    errored: null,
    closed: false,
    closeEmitted: false,
    defaultEncoding: 'utf8',
    awaitDrainWriters: null,
    multiAwaitDrain: false,
    readingMore: false,
    decoder: null,
    encoding: null,
    [Symbol(kPaused)]: null
  },
  _events: [Object: null prototype] { close: [Function: remove] },
  _eventsCount: 1,
  _maxListeners: undefined,
  _pos: 0,
  _writeStream: WriteStream {
    _writableState: WritableState {
      objectMode: false,
      highWaterMark: 16384,
      finalCalled: false,
      needDrain: true,
      ending: false,
      ended: false,
      finished: false,
      destroyed: false,
      decodeStrings: true,
      defaultEncoding: 'utf8',
      length: 63781,
      writing: true,
      corked: 0,
      sync: false,
      bufferProcessing: false,
      onwrite: [Function: bound onwrite],
      writecb: [Function: nop],
      writelen: 63781,
      afterWriteTickInfo: null,
      buffered: [],
      bufferedIndex: 0,
      allBuffers: true,
      allNoop: true,
      pendingcb: 1,
      prefinished: false,
      errorEmitted: false,
      emitClose: true,
      autoDestroy: false,
      errored: null,
      closed: false
    },
    _events: [Object: null prototype] {
      error: [Array],
      unpipe: [Function: onunpipe],
      close: [Function],
      finish: [Function],
      ready: [Function],
      drain: [Function: pipeOnDrainFunctionResult]
    },
    _eventsCount: 6,
    _maxListeners: undefined,
    _fd: null,
    _path: null,
    _pos: 0,
    _readStreams: Set(1) { [Circular *1] },
    _released: false,
    _cleanupSync: [Function (anonymous)],
    [Symbol(kCapture)]: false
  },
  [Symbol(kCapture)]: false
}

Upload success:

enter image description here

源代码:https://github.com/mrdulin/apollo-graphql-tutorial/tree/master/src/file-upload


1
这与通常众所周知的 https://github.com/jaydenseric/graphql-upload#examples 参数处理不同 - 在 upload 变量/参数内部有额外的 file 级别? - xadm
@xadm 我知道这个例子。但是在这个例子中,upload 参数内的 file 字段确实存在。我已经添加了我的源代码链接,请查看。 - Lin Du
@slideshowp2 我在这一行遇到了问题:const { filename, mimetype, createReadStream } = await file; 报错信息是 Cannot destructure property 'filename' of '(intermediate value)' as it is undefined。我认为xadm是正确的,这不是graphql-upload处理上传的方式。 - BraveEvidence
@Pritish 看起来我遇到了这个问题 - Lin Du
@slideshowp2 我在 graphql-upload 上提出了同样的问题,但作者关闭了它,说这个问题是来自 apollo-server 的一面。 - BraveEvidence

0
const { filename, mimetype, createReadStream } = await file.promise;

1
这个在浏览器上能用吗? - ndotie

0

在升级到apollo-server v3后,我成功解决了错误。我认为v2graphql-upload库存在某些冲突。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接