如何在Meteor+Apollo环境中配置graphql-upload
在Meteor + Apollo Server环境中配置graphql-upload
我之前在Meteor+Apollo项目里配置文件上传的时候也踩过不少坑,刚好能给你分享下亲测有效的配置步骤——核心是要适配Meteor的请求处理流程,不能直接照搬官方文档的配置:
1. 先装对依赖
首先确保安装了graphql-upload,注意和你的Apollo Server版本匹配:如果是Apollo Server 3及以上,推荐用graphql-upload@16.x版本。
npm install graphql-upload # 或者用yarn yarn add graphql-upload
2. 调整Apollo Server的启动代码
这是最关键的一步!因为Meteor的WebApp.connectHandlers是按顺序执行中间件的,我们得先挂载graphql-upload的中间件,再启动Apollo Server并挂载它的处理逻辑,同时还要禁用Apollo自带的上传处理避免冲突:
import { ApolloServer } from '@apollo/server'; import { expressMiddleware } from '@apollo/server/express4'; import { graphqlUploadExpress } from 'graphql-upload'; import WebApp from 'meteor/webapp'; import express from 'express'; // 先创建一个Express实例,因为graphql-upload依赖Express的中间件机制 const app = express(); // 挂载graphql-upload中间件,还可以配置文件大小、数量限制(可选) app.use(graphqlUploadExpress({ maxFileSize: 10 * 1024 * 1024, // 限制单文件10MB maxFiles: 5 // 最多同时传5个文件 })); async function startApolloServer() { const server = new ApolloServer({ playground: true, schema, plugins: [ /* 你的插件配置 */ ], context: async({req}) => ({ user: await getUser(req.headers.authorization) }), // 禁用Apollo自带的上传处理,防止和graphql-upload冲突 allowBatchedHttpRequests: true, }); await server.start(); // 把Apollo的Express中间件挂载到我们的Express app上 app.use('/graphql', expressMiddleware(server, { context: async({req}) => ({ user: await getUser(req.headers.authorization) }) })); // 最后把整个Express app挂载到Meteor的connectHandlers上 WebApp.connectHandlers.use(app); } // 启动服务,别忘了捕获错误 startApolloServer().catch(err => console.error('Apollo Server启动失败:', err));
3. 定义上传相关的GraphQL Schema和Resolver
接下来就可以按常规方式写上传的Schema和处理逻辑了,举个简单的例子:
Schema 定义
type File { filename: String! mimetype: String! encoding: String! url: String! # 返回给前端的文件访问地址 } type Mutation { uploadFile(file: Upload!): File! }
Resolver 实现
import { createWriteStream } from 'fs'; import { resolve } from 'path'; import fs from 'fs'; // 先确保上传目录存在,避免报错 const uploadDir = resolve(process.cwd(), 'public/uploads'); if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } const resolvers = { Mutation: { uploadFile: async (_, { file }) => { const { createReadStream, filename, mimetype, encoding } = await file; // 把文件流写到本地的public/uploads目录(你也可以改成云存储,比如S3) const stream = createReadStream(); const filePath = resolve(uploadDir, filename); // 等待文件写入完成 await new Promise((resolve, reject) => { stream.pipe(createWriteStream(filePath)) .on('finish', resolve) .on('error', reject); }); return { filename, mimetype, encoding, url: `/uploads/${filename}` // 前端可以通过这个URL访问上传后的文件 }; } } };
4. 前端也要配套调整
最后别忘了在前端的Apollo Client配置里,用createUploadLink代替默认的createHttpLink,不然前端没法正确发送文件:
import { createUploadLink } from 'apollo-upload-client'; import { ApolloClient, InMemoryCache } from '@apollo/client'; const client = new ApolloClient({ link: createUploadLink({ uri: '/graphql' }), cache: new InMemoryCache() });
内容的提问来源于stack exchange,提问作者freeseamew
相关产品推荐
相关产品推荐

