Vue Apollo上传文件触发Node Maximum call stack size exceeded错误如何解决
问题排查与解决方案
这个Maximum call stack size exceeded at _openReadFs栈溢出报错,核心原因是废弃依赖和重复的上传中间件逻辑冲突,按以下步骤修复即可:
1. 卸载废弃后端依赖
apollo-upload-server早已停止维护,和Apollo Server 2.x及以上版本的内置上传逻辑存在冲突,先执行卸载:
npm uninstall apollo-upload-server
2. 移除重复的上传中间件
删除server.js中手动引入的apolloUploadExpress中间件代码,Apollo Server 2.x以上版本默认自带上传处理能力,只要在schema中声明了scalar Upload就会自动启用,重复添加中间件会导致文件流被反复读取,触发循环调用栈溢出。
如果需要限制上传文件大小和数量,直接在Apollo Server初始化配置中添加uploads参数即可:
const server = new ApolloServer({ typeDefs: logoUploadTypeDefs, resolvers, // 上传配置直接写在这里 uploads: { maxFileSize: 1000000000, maxFiles: 10 }, // 其余原有配置保持不变 })
3. 验证Resolver逻辑
确保上传Resolver中没有重复消费文件流,正确写法参考:
// 引入graphql-upload提供的标量实现 const { GraphQLUpload } = require('graphql-upload') const resolvers = { Upload: GraphQLUpload, Mutation: { uploadLogo: async (_, { file }) => { // 单次解析文件对象 const { createReadStream, filename, mimetype, encoding } = await file // 后续处理文件存储逻辑,不要重复调用createReadStream // ... 你的存储代码 return { _id: '自定义文件ID', path: '文件存储路径', filename, mimetype, encoding, // 其余返回字段 } } } }
4. 可选:前端依赖升级(推荐)
apollo-boost-upload同样属于废弃的boost系列包,如果你的Apollo Client版本在3.x以上,建议替换为官方标准依赖,避免兼容性问题:
先安装依赖:
npm install @apollo/client apollo-upload-client
修改客户端配置:
import { ApolloClient, InMemoryCache, from } from "@apollo/client"; import { createUploadLink } from "apollo-upload-client"; import { setContext } from "@apollo/client/link/context"; import { onError } from "@apollo/client/link/error"; import VueApollo from "vue-apollo"; // 上传链路 const uploadLink = createUploadLink({ uri: "http://localhost:4000/graphql", credentials: "include", }); // 授权链路 const authLink = setContext((_, { headers }) => { const token = localStorage.getItem("someToken") || ""; return { headers: { ...headers, authorization: `Bearer ${token}`, }, }; }); // 错误处理链路 const errorLink = onError(({ graphQLErrors, networkError }) => { if (networkError) { console.log("[networkError]", networkError); } if (graphQLErrors) { for (const error of graphQLErrors) { console.dir(error); if (error.name === "AuthenticationError") { store.commit("setError", error); store.dispatch("signUserOut"); } } } }); // 初始化客户端 export const defaultClient = new ApolloClient({ link: from([errorLink, authLink, uploadLink]), cache: new InMemoryCache({ addTypename: false, }), });
修改后原有前端上传逻辑不需要改动,直接正常调用即可。
内容的提问来源于stack exchange,提问作者rhythmo
相关产品推荐
相关产品推荐

