【问题标题】:How to forward a multipart/form-data POST request in Node to another service如何将 Node 中的 multipart/form-data POST 请求转发到另一个服务
【发布时间】:2019-04-12 16:56:33
【问题描述】:

我需要从客户端向我的 Node.js 服务器发送一个 multipart/form-data POST(xliff 文件),然后在 Node.js 中捕获数据并将该 POST 转发到另一个 Java 服务。

我已经使用 multerexpress-fileupload 来解析表单数据流并在 Node.js 中捕获 xliff 的缓冲区,并且都将文件内容作为缓冲区提供给我。

但是,我似乎无法在 Node 层重新创建 FormData 对象以将 POST 转发到 Java 服务。

我继续收到错误消息“连接已终止解析多部分数据”,或者 Java 服务根本没有响应。

我还尝试使用tmp 库在本地创建一个临时文件来写入缓冲区,然后尝试FormData('file', fs.createReadStream(<path>)),但这似乎对我也不起作用......虽然我'我不确定我做的是否正确。

直接在浏览器中使用完全相同的doPOST 请求可以正常工作,但是一旦我尝试在节点层捕获调用,然后将 POST 转发到 Java 服务,它就不再适合我了。

.

const multer = require('multer');
const upload = multer();

router.post('/', upload.any(), (req, res) => {
  const { headers, files } = req;

  console.log('--------------- files:', files[0]); // object with buffer, etc.

  const XMLString = files[0].buffer.toString('utf8'); // xml string of the xliff

  const formFile = new FormData();
  formFile.append('file', XMLString);

  console.log('--------------- formFile:', formFile); // FormData object with a key of _streams: [<xml string with boundaries>, [Function: bound ]]

  headers['Content-Type'] = 'multipart/form-data';
  const url = 'some/url/to/Java/service'

  doPOST(url, formFile, {}, headers)
    .catch((error) => {
      const { status, data } = error.response;
      res.status(status).send(data);
    })
    .then(({ data }) => {
      res.send(data);
    });
});

【问题讨论】:

  • 您不必将文件缓冲区转换为 xml 字符串。而是直接将应用程序 files[0] 作为带有标题的缓冲区数组 headers['Content-Type'] = 'multipart/form-data';
  • 直接传递 xliff 的缓冲区对我来说也不起作用。我也试过了。
  • 发现一篇文章做同样的事情。看看medium.com/technoetics/…
  • 谢谢,已经读过 :) 那篇文章还提到了在 Node 中捕获表单数据,但没有提到如何将表单数据转发到新服务,这是我的问题
  • 如果doPost 可以接受流,您可以将req 直接流式传输到Java 服务器,无需本地解析。

标签: node.js post form-data


【解决方案1】:

您可以直接将buffer 传递给您的表单数据,但是您还需要指定filename 参数。

const multer = require('multer');
const upload = multer();

router.post('/', upload.any(), (req, res) => {
  const { headers, files } = req;
  const { buffer, originalname: filename } = files[0];

  const formFile = new FormData();
  formFile.append('file', buffer, { filename });

  headers['Content-Type'] = 'multipart/form-data';
  const url = 'some/url/to/Java/service'

  doPOST(url, formFile, {}, headers)
    .catch((error) => {
      const { status, data } = error.response;
      res.status(status).send(data);
    })
    .then(({ data }) => {
      res.send(data);
    });
});

【讨论】:

  • 感谢您的回复!如果我有时间解决这个问题,我会用你的代码再试一次。
  • 我试图使用 FormData 和 multer memoryStorage 将文件数组传递给 Spring WS。显然,我所缺少的只是选项中的文件名。感谢您指出这一点,我在文档中的任何地方都看不到它。虽然显式设置 Content-Type 标头导致“FileUploadException:请求被拒绝,因为没有找到多部分边界”
  • 谢谢。我一直在试图弄清楚如何为 POST 使用缓冲区,而我所缺少的只是 filename
【解决方案2】:

对于面对"FileUploadException: the request was rejected because no multipart boundary was found"的人来说,这是你需要做的。

https://github.com/axios/axios/issues/1006

这为我解决了这个问题。不是 axios 特有的,我们只需要转发发送请求时计算的 formData 头即可。

对于多部分/表单数据,边界是根据文件内容计算的。浏览器会自动执行此操作。但在 node.js 中,我们需要显式转发这些。感谢form-data npm 包,这些都是为您完成的。

【讨论】:

    【解决方案3】:

    这是我在 NodeJS 中提出的解决方案的伪代码示例。 我在 ApolloGQL 中使用了类似的解决方案,但它同样适用于 ExpressJS。 因此,我的示例的模式更类似于 ExpressJS。

    在下面的例子中展示了如何传递一个 JSON 对象 以及在发送之前将文件缓冲区传递到 FormData。

    const FormData = require('form-data'); // version ^3.0.0
    
    router.post('/', async (req, res) => {
      const { body } = req;
      const { stringContentOfSomeFile } = body;
      
      // create formData for your request:
      const thisForm = new FormData();
    
      // passing a JSON object:
      // must declare "contentType: application/json" to avoid 415 status response from some systems:
      const someJson = JSON.stringify({  key: 'value', otherKey: 'otherValue' });
      thisForm.append('data', someJson, { contentType: 'application/json' });
      
      // passing a file buffer:
      const fileBuffer = Buffer.from(stringContentOfSomeFile, 'utf-8');
      thisForm.append('form_field_name_here', fileBuffer, 'file_name_here');
    
      const response = await axios.post('/path/to/endpoint', thisForm, {
        // must getHeaders() from "formData" to define the boundaries of the appended data:
        headers: { ...thisForm.getHeaders() },
      });
    
      // do whatever you need with the response:
      res.send(response);
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-25
      • 1970-01-01
      • 1970-01-01
      • 2017-10-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多