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

如何从Node.js服务器向Rails GraphQL后端实现服务器到服务器的本地文件上传?

我刚好处理过类似的Node.js服务器端向Rails GraphQL后端上传文件的场景,给你梳理下正确的解决思路和代码实现:

解决Node.js服务器端Apollo文件上传的问题

你遇到的核心问题是:浏览器环境的File对象和Node.js环境的文件操作结构完全不同,apollo-upload-client在Node环境下需要特定格式的对象才能识别为可上传文件,直接传fs.ReadStream或Node版Blob都不符合要求。

正确的方案:构造符合Apollo上传要求的对象

apollo-upload-client在Node环境中会识别包含以下三个属性的对象作为上传文件:

  • createReadStream: 返回文件读取流的函数
  • filename: 后端将接收的文件名
  • mimetype: 文件的MIME类型(比如image/jpeg、text/plain)

下面是完整的可运行代码:

首先导入所需模块:

import fs from "fs"
import { ApolloClient, InMemoryCache } from "@apollo/client"
import { createUploadLink } from "apollo-upload-client"
import type { NextApiRequest, NextApiResponse } from "next"
import * as Generated from "src/generated/graphql"

创建一个工具函数来生成符合要求的上传对象:

// 工具函数:生成Apollo上传所需的文件对象
const generateUploadFile = (filePath: string, filename: string, mimetype: string) => {
  return {
    filename,
    mimetype,
    createReadStream: () => fs.createReadStream(filePath),
  }
}

然后在你的API路由中使用这个函数:

const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: createUploadLink({
    uri: "http://backend:3000/graphql",
  }),
})

// 验证连接的代码可以保留
client
  .query<Generated.TestFieldQuery, Generated.TestFieldQueryVariables>({
    query: Generated.TestFieldDocument,
    variables: {},
  })
  .then(({ data }) => {
    console.log("连接正常,返回数据:", data)
  })

export default async (req: NextApiRequest, res: NextApiResponse) => {
  try {
    // 构造上传文件对象
    const file = generateUploadFile("./test.jpg", "test.jpg", "image/jpeg")
    
    const { data } = await client.mutate<
      Generated.TestMutationMutation,
      Generated.TestMutationMutationVariables
    >({
      mutation: Generated.TestMutationDocument,
      variables: {
        input: {
          file,
        },
      },
      fetchPolicy: "no-cache",
    })

    console.log("文件上传成功:", data)
    res.status(200).json({ success: true, data })
  } catch (error) {
    console.error("文件上传失败:", error)
    res.status(500).json({ 
      success: false, 
      error: error instanceof Error ? error.message : "未知错误" 
    })
  }
}

为什么之前的尝试失败?

  • 直接传fs.createReadStream:这个返回的ReadStream对象缺少filename和mimetype属性,后端无法将其识别为一个合法的上传文件。
  • 使用Node版Blob:Node.js从buffer模块导入的Blob和浏览器原生Blob结构差异很大,apollo-upload-client在Node环境下不把它当作上传文件处理,因此会报错{} is not a valid upload。

后端兼容性说明

你的Rails后端已经配置了apollo_upload_server,它会自动将这种格式的上传解析为ActionDispatch::Http::UploadedFile对象,和客户端上传的格式完全一致,所以不需要修改任何后端代码。

另外要注意,必须使用createUploadLink作为Apollo客户端的链接,不能用普通的HttpLink,否则文件上传的多部分表单请求无法被正确处理。

内容的提问来源于stack exchange,提问作者kukrt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 20:32:35