【问题标题】:createReadStream() throwing RangeError: Maximum call stack size exceeded when uploading filecreateReadStream() 抛出 RangeError:上传文件时超出最大调用堆栈大小
【发布时间】:2020-04-24 12:15:03
【问题描述】:

我正在尝试使用 Apollo Server 的 Upload 标量将文件直接发送到 S3。我的架构:

const { gql } = require('apollo-server-express')

module.exports = gql`

extend type Mutation {
  createPicture(
    name: String!
    picture: Upload!
  ): Picture!
}

type Picture {
  name: String!
  picture: String!
}
`

解析器:

const { combineResolvers } = require('graphql-resolvers')
const isAuthenticated = require('./auth')
const { uploadPhoto } = require('../services/picture')

module.exports = {
  Mutation: {
    createPicture: combineResolvers(
      isAuthenticated,
      async (
        parent,
        { name, picture = null },
        { models, me }
      ) => {
        const { createReadStream, filename, mimetype, encoding } = await picture
        // Does not get past this line
        const stream = createReadStream()

        uploadPhoto(stream, filename)

        const pictureModel = models.Picture.create({
           name,
           picture
        })
        return pictureModel
      }
    )
  }
}

但是我的代码错误是这样的:

internal/util.js:55
  function deprecated(...args) {
                     ^

RangeError: Maximum call stack size exceeded
    at ReadStream.deprecated [as open] (internal/util.js:55:22)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)
    at _openReadFs (internal/fs/streams.js:123:12)
    at ReadStream.<anonymous> (internal/fs/streams.js:116:3)
    at ReadStream.deprecated [as open] (internal/util.js:70:15)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)
    at _openReadFs (internal/fs/streams.js:123:12)
    at ReadStream.<anonymous> (internal/fs/streams.js:116:3)
    at ReadStream.deprecated [as open] (internal/util.js:70:15)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)
    at _openReadFs (internal/fs/streams.js:123:12)
    at ReadStream.<anonymous> (internal/fs/streams.js:116:3)
    at ReadStream.deprecated [as open] (internal/util.js:70:15)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)
    at _openReadFs (internal/fs/streams.js:123:12)
    at ReadStream.<anonymous> (internal/fs/streams.js:116:3)
    at ReadStream.deprecated [as open] (internal/util.js:70:15)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)
    at _openReadFs (internal/fs/streams.js:123:12)
    at ReadStream.<anonymous> (internal/fs/streams.js:116:3)
    at ReadStream.deprecated [as open] (internal/util.js:70:15)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)

注意:我确定图片发送正确,因为filename 是正确的

【问题讨论】:

标签: node.js graphql apollo-server express-graphql


【解决方案1】:

TLDR:默认 Apollo 服务器文件上传在节点 >=13 中不起作用。通过使用graphql-upload 服务器文件上传覆盖 Apollo 的服务器文件上传来修复它

npm install graphql-upload

覆盖TypeDefs中的默认Apollo上传类型

const typeDefs = gql`
  scalar Upload
  ...
 `

覆盖index.js中的默认Apollo上传类型

const { GraphQLUpload } = require('graphql-upload')
const { graphqlUploadExpress } = require('graphql-upload')
const express = require('express')
 
const app = express()

app.use(graphqlUploadExpress({ 
  maxFileSize: 10000000, 
  maxFiles: 10 
}))

const server = new ApolloServer({
  typeDefs,
  resolvers: {
    Upload: GraphQLUpload,
    ...resolvers
  }
  uploads: false
  ...
})

server.applyMiddleware({
  app
})

【讨论】:

    【解决方案2】:

    我已阅读 graphql-upload 文档,但找不到一个可靠的示例来说明如何在 NodeJS 14 上将图形上传与 apollo-server 一起使用。 基于示例应用程序(在旧的 graphql-upload 版本的 apollo-server 上工作,在 NodeJS 14 上失败)和堆栈溢出的答案,我设法创建了一个功能齐全的示例。

    原例:https://github.com/DNature/apollo-upload

    我使用apollo-server-express,而不是 apollo-server。

    使用 NodeJS 14、graphql-upload@12.0.0 和 apollo-server-express@2.25.1:

    index.js

    import { ApolloServer } from "apollo-server-express";
    import express from "express";
    import { graphqlUploadExpress } from "graphql-upload";
    import typeDefs from "./typeDefs";
    import resolvers from "./resolvers";
    
    // Import your database configuration
    import connect from "./db";
    
    export default (async function () {
      try {
        await connect.then(() => {
          console.log("Connected ? To MongoDB Successfully");
        });
    
        const server = new ApolloServer({
          uploads: false, // Disables the bundled ApolloServer old graphql-upload that doesn't work on NodeJS 14
          typeDefs,
          resolvers,
        });
        await server.start();
    
        const app = express();
        app.use(graphqlUploadExpress({ maxFileSize: 1000000000, maxFiles: 10 }));
        server.applyMiddleware({ app });
    
        await new Promise((resolve) => app.listen({ port: 7000 }, resolve));
        console.log(
          `? Server ready at http://localhost:7000${server.graphqlPath}`
        );
      } catch (err) {
        console.error(err);
      }
    })();
    

    在 typeDefs.gql 中需要定义标量 Upload:

    import { gql } from "apollo-server-express";
    
    export default gql`
      scalar Upload
    
      type File {
        id: ID!
      ...
    

    在 resolvers.js 中需要定义上传的解析器:

    ...
    
    import { GraphQLUpload } from 'graphql-upload';
    
    ...
    
    export default {
      Upload: GraphQLUpload,
    
      Query: {
        hello: () => "Hello world"
      },
      Mutation: {
    ...
    

    终于从邮递员上传:

    注意:键 0 的类型是 File,而不是 Text!

    【讨论】:

      【解决方案3】:

      将此添加到您的 package.json 中

       "resolutions": {
          "graphql-upload": "^11.0.0"
        }
      

      然后在脚本中添加这个

      "scripts": {
          ....
          "preinstall": "npx npm-force-resolutions", //This one
          ....
      }
      

      然后你需要做 npm install。完成

      来源:graphql-upload

      【讨论】:

      • 谢谢,这为我节省了很多
      【解决方案4】:

      由于这是 fs-capacitor 的错误,这将有所帮助,正如我们在 issue 中看到的那样

      在节点 14.16.1 中为我工作,配置如下:

      "resolutions": {
          "fs-capacitor": "^6.2.0",
          "graphql-upload": "^11.0.0"
      }
      

      我需要在“脚本”中添加强制分辨率

      "scripts": {
          ....
          "preinstall": "npx npm-force-resolutions"
      }
      
      

      删除 ./node_modules 并使用 npm install 再次安装依赖项。

      【讨论】:

      • 谢谢,这为我节省了很多
      • 好的,但首先加载它们的是哪个包?
      【解决方案5】:

      我已经多次处理这个问题

      问题是旧的 graphql-upload 更准确​​的版本 8 使用了节点开放流功能,该功能已被弃用,在 13.x 和更旧的节点版本中不再可用。

      所以解决方案是您可以使用 nvm 将节点版本设置为 12 或使用 package.json 文件中的分辨率。 第一个解决方案(在您最喜欢的终端中):

      nvm install 12; nvm use 12
      

      第二个解决方案(在 package.json 中):

      "resolutions": {
          "**/**/fs-capacitor":"^6.2.0",
          "**/graphql-upload": "^11.0.0"
        }
      

      这也是我几个月来一直在处理的一个问题,我认为阿波罗团队真的不喜欢更新他们的依赖关系。

      【讨论】:

        【解决方案6】:

        使用:

            "apollo-server": "^2.18.2",
            "apollo-server-express": "2.18.2",
            "aws-sdk": "^2.771.0",
            "express-fileupload": "^1.2.0",
            "graphql": "^15.3.0",
            "graphql-upload": "^11.0.0",
            "fs-capacitor": "^6.2.0",
        

        我通过安装最新的fs-capacitor 作为依赖项解决了这个问题

        yarn add fs-capacitor
        

        【讨论】:

        • 添加 fs-capacitor 6.2.0 作为解决方案对我有用。
        【解决方案7】:

        将此添加到 package.json:

        "resolutions": {
            "**/**/fs-capacitor":"^6.2.0",
            "**/graphql-upload": "^11.0.0"
          }
        

        来源:https://github.com/jaydenseric/graphql-upload/issues/170#issuecomment-641938198

        【讨论】:

        【解决方案8】:

        我在节点版本 14 中也出现了这个错误! 我解决了如下:

        1. 安装最新版本的graphql-upload!

        2. 使用 graphqlUploadExpress 中间件来定义最大文件限制。

          import { graphqlUploadExpress } from "graphql-upload";
          const app = express()
          app.use(graphqlUploadExpress({ maxFileSize: 1000000000, maxFiles: 10 }));
          
        3. 在初始化 ApolloServer 时将上传设置为 false

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

        【讨论】:

        • 您能解释一下为什么我们需要将上传设置为 false 吗?为什么 OP 需要安装一个单独的库才能让它现在工作?
        • @JohhanSantana Apollo 服务器捆绑在节点 14 上损坏的 graphql-upload 克隆中。要使用较新的固定 graphql-upload 包,您需要告诉 apollo 不要使用它的捆绑包。然后通过使用 express 注册 body 处理程序并添加上传模式的内容来自己使用它。
        • 这个答案确实是正确的,只记得在应用Apollo服务器中间件之前调用app.use(graphqlUploadExpress({ maxFileSize: 1000000000, maxFiles: 10 }));
        • 嗨,伙计。我这样做了,但现在我收到另一个错误:“消息”:“args.file.then 不是函数”,这是我的代码: const singleUpload = (parent, args) => { return args.file.then((file) => { const { createReadStream, filename } = file const fileStream = createReadStream() fileStream.pipe(fs.createWriteStream(../../assets/img/grid/${filename})) return file }) }
        • @JulianoCosta 您可能忘记将其添加到您传递到架构中的解析器中:resolvers: { Upload: GraphQLUpload, } 根据文档:上传:github.com/jaydenseric/graphql-upload#class-graphqlupload 在版本 8 中,它在没有此解析器的情况下工作。跨度>
        【解决方案9】:

        原来是graphql-upload 中的this 错误。降级到节点 12 并且已修复(那里列出的解决方案对我没有帮助)

        【讨论】:

        猜你喜欢
        • 2018-02-06
        • 1970-01-01
        • 1970-01-01
        • 2021-05-30
        • 2021-07-11
        • 2019-07-05
        • 2015-04-26
        相关资源
        最近更新 更多