如何将Node中的多部分/表单数据POST请求转发到另一个服务 [英] How to forward a multipart/form-data POST request in Node to another service

查看:397
本文介绍了如何将Node中的多部分/表单数据POST请求转发到另一个服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要从客户端向我的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服务,则对我来说不再起作用. /p>

.

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);
    });
});

解决方案

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

I need to send a multipart/form-data POST (xliff file) from the client to my Node.js server, and then capture the data in Node.js and forward that POST to another Java service.

I've used both multer and express-fileupload to parse the form-data stream and capture a Buffer of the xliff in Node.js and both gave me the file with its content as a buffer just fine.

However, I cannot seem to re-create a FormData object in the Node layer to forward the POST to the Java service.

I continue to get the error message "Connection terminated parsing multipart data" or just no response at all form the Java service.

I've Also attempted to use the tmp library to create a temporary file locally to write the buffer and then try to FormData('file', fs.createReadStream(<path>)), but that didn't seem to work for me either... though I'm not sure I was doing it correctly.

Using the exact same doPOST request directly form the Browser works fine, but once I try to capture the call in the Node layer and then forward the POST to the Java service, it doesn't work for me anymore.

.

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);
    });
});

解决方案

This is a pseudo code example of the solution I came up with in NodeJS. I used a similar solution in ApolloGQL, but it applies all the same to ExpressJS. Hence, my example is in a pattern more akin to ExpressJS.

In the below example shows how to pass a JSON object as well as passing a file buffer into the FormData before sending it off.

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);
});

这篇关于如何将Node中的多部分/表单数据POST请求转发到另一个服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆