You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 12:44:11