如何对上传到 Node Express 服务器的文件进行 post 后续处理,然后再上传到另一个 API

How to do a follow on post of a file uploaded to a Node Express server onward to another API

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

我试过使用 multer 和文件上传包,但是 运行 在尝试上传到第 3 方 API 时遇到了这两个问题。 post 到 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);
        }
    })

使用文件上传包的代码将上传的文件放到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);
        }
    })

我已经注销了 posted 到 API 的文件对象。在成功的post中,从节点服务器上的文件系统中取出是:

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'
}

在 post 到 API 期间使用 Multer 或文件数据方法,两者都失败了,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'
}

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

我看到两件事:

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

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

我写了一篇关于如何 Send a File With Axios in Node.js 的文章。它涵盖了一些需要避免的常见陷阱,我认为您会学到一些有用的东西。

问题是缺少文件名参数,正如@Maximorlov 在他的第二点中正确指出的那样。

如果有人想在不阅读评论的情况下看到正确的解决方案,我将其放在下面。

    .post('/update', upload.single('file'),  async (req, res, next) => {
        try {
            const fileBuffer = req.file.buffer;
            const form = new FormData();
            form.append('file', fileBuffer, req.file.originalname);
            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);
        }
    })