首页 > 解决方案 > 如何将上传到 Node Express 服务器的文件发布到另一个 API

问题描述

我们在 Node 中有一个 Express 服务器,在一个路由上我们上传一个文件,然后需要将该文件继续发送到另一个端点进行处理,初始客户端无法访问该端点。大多数用例似乎依赖于从本地服务器获取路径,但在我们的例子中,本地服务器上不存在该文件,我们将其作为上传对象。

我尝试过使用 multer 和文件上传包,但是在尝试上传到 3rd 方 API 时遇到了问题。两者都发布到 3rd Party API,然后失败。但是,如果我使用来自 Express 服务器的 fs 在本地上传文件,那么它会很好地上传到 API。

因此,我可以先将其保存在本地,然后使用本地文件发送并删除它,但这感觉好像没有必要。

使用 Multer 的代码,将文件放到 req.file 中:

    .post('/update', upload.single('file'),  async (req, res, next) => {
        try {
            const fileBuffer = req.file.buffer;
            const form = new FormData();
            form.append('file', fileBuffer);
            const boundary = form.getBoundary();
            const config = {
                headers: {
                    "Content-Type": `multipart/form-data; boundary=${boundary}`
            }};
            const axiosInst = axios.create(config);
            const url = `${baseAPI}/translate`;
            const { status, data } = await axiosInst.post(url, form);
            return res.status(status).json(data);
        } catch (error) {
            next(error);
        }
    })

使用 file-upload 包的代码将上传的文件放到 req.files 中:

    .post('/update', async (req, res, next) => {
        try {
            let { file } = req.files;
            fileBuffer = Buffer.from(JSON.stringify(file));
            const form = new FormData();
            form.append('file', fileBuffer);
            const boundary = form.getBoundary();
            const config = {
                headers: {
                    "Content-Type": `multipart/form-data; boundary=${boundary}`
            }};
            const axiosInst = axios.create(config);
            const url = `${baseAPI}/translate`;
            const { status, data } = await axiosInst.post(url, form);
            return res.status(status).json(data);
        } catch (error) {
            next(error);
        }
    })

我已经注销了发布到 API 的文件对象。在成功的帖子中,从节点服务器上的文件系统中获取它是:

FormData {
  _overheadLength: 237,
  _valueLength: 0,
  _valuesToMeasure: [
    ReadStream {
      _readableState: [ReadableState],
      readable: true,
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      path: 'c:\\work\\Test Template Upload Facility.docx',
      fd: null,
      flags: 'r',
      mode: 438,
      start: undefined,
      end: Infinity,
      autoClose: true,
      pos: undefined,
      bytesRead: 0,
      closed: false,
      emit: [Function],
      [Symbol(kFs)]: [Object],
      [Symbol(kCapture)]: false,
      [Symbol(kIsPerformingIO)]: false
    }
  ],
  writable: false,
  readable: true,
  dataSize: 0,
  maxDataSize: 2097152,
  pauseStreams: true,
  _released: false,
  _streams: [
    '----------------------------344728646415746168257760\r\n' +
      'Content-Disposition: form-data; name="file"; filename="Test Template Upload Facility.docx"\r\n' +
      'Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document\r\n' +
      '\r\n',
    DelayedStream {
      source: [ReadStream],
      dataSize: 0,
      maxDataSize: Infinity,
      pauseStream: true,
      _maxDataSizeExceeded: false,
      _released: false,
      _bufferedEvents: [Array],
      _events: [Object: null prototype],
      _eventsCount: 1
    },
    [Function: bound ]
  ],
  _currentStream: null,
  _insideLoop: false,
  _pendingNext: false,
  _boundary: '--------------------------344728646415746168257760'
}

在使用 Multer 或文件数据方法的 API 帖子中,两者都失败了,Multer 或文件数据之间的文件对象非常相似,并按如下方式注销:

FormData {
  _overheadLength: 143,
  _valueLength: 12024,
  _valuesToMeasure: [],
  writable: false,
  readable: true,
  dataSize: 0,
  maxDataSize: 2097152,
  pauseStreams: true,
  _released: false,
  _streams: [
    '----------------------------486237832288086608829884\r\n' +
      'Content-Disposition: form-data; name="file"\r\n' +
      'Content-Type: application/octet-stream\r\n' +
      '\r\n',
    <Buffer 50 4b 03 04 14 00 06 00 08 00 00 00 21 00 df a4 d2 6c 5a 01 00 00 20 05 00 00 13 00 08 02 5b 43 6f 6e 74 65 6e 74 5f 54 79 70 65 73 5d 2e 78 6d 6c 20 ... 11974 more bytes>,
    [Function: bound ]
  ],
  _currentStream: null,
  _insideLoop: false,
  _pendingNext: false,
  _boundary: '--------------------------486237832288086608829884'
}

我当然可以将文件保存在本地,并且可能必须这样做,但如果有人能找到避免这样做的方法,我将不胜感激,谢谢。

标签: javascriptnode.jsexpressfile-uploadmulter

解决方案


我看到两件事:

  1. 您正在构建表单,但最终您发送的是文件,而不是表单。将您的代码更改为:await axiosInst.post(url, form)

  2. 在 Node.js 中将文件附加到表单时,您必须使用第三个参数(文件名)。以 multer 为例,您可以:form.append('file', fileBuffer, req.file.originalname);

我写了一篇关于如何在 Node.js 中使用 Axios 发送文件的文章。它涵盖了一些要避免的常见陷阱,我认为您会学到一些有用的东西。


推荐阅读