如何将Node中的多部分/表单数据POST请求转发到另一个服务

时间:2018-11-09 05:30:02

标签: node.js post form-data

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

我已经使用multerexpress-fileupload来解析表单数据流并在Node.js中捕获xliff的Buffer,并且两者都给了我带有其内容的文件作为缓冲区很好。

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

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

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

直接在浏览器中直接使用完全相同的doPOST请求可以正常工作,但是一旦我尝试在Node层中捕获该调用,然后将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);
    });
});

3 个答案:

答案 0 :(得分:0)

您可以直接将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);
    });
});

答案 1 :(得分:0)

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

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

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

对于multipart / form-data,边界是根据文件内容计算的。浏览器会自动执行。但是在node.js中,我们需要显式转发那些。感谢form-data npm软件包,这些都可以为您完成。

答案 2 :(得分:0)

这是我在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);
});