如何将 Node 中的 multipart/form-data POST 请求转发到另一个服务
How to forward a multipart/form-data POST request in Node to another service
我需要从客户端发送一个multipart/form-data POST(xliff文件)到我的Node.js服务器,然后在Node.js中捕获数据并转发POST 到另一个 Java 服务。
我已经使用 multer
和 express-fileupload
来解析表单数据流并在 Node.js 中捕获 xliff 的缓冲区,并且都给了我包含其内容的文件作为缓冲区就好了。
但是,我似乎无法在节点层中重新创建 FormData 对象以将 POST 转发到 Java 服务。
我继续收到错误消息 "Connection terminated parsing multipart data" 或者根本没有来自 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);
});
});
您可以直接将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);
});
});
对于面临"FileUploadException: the request was rejected because no multipart boundary was found"
的人来说,这是你需要做的。
https://github.com/axios/axios/issues/1006
这解决了我的问题。它不是 axios 特定的,我们只需要转发发送请求时计算的 formData headers。
对于multipart/form-data,边界是根据文件内容计算的。浏览器会自动执行此操作。但是在 node.js 中,我们需要明确转发这些。感谢 form-data
npm package 这些都为你完成了。
这是我在 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);
});
我需要从客户端发送一个multipart/form-data POST(xliff文件)到我的Node.js服务器,然后在Node.js中捕获数据并转发POST 到另一个 Java 服务。
我已经使用 multer
和 express-fileupload
来解析表单数据流并在 Node.js 中捕获 xliff 的缓冲区,并且都给了我包含其内容的文件作为缓冲区就好了。
但是,我似乎无法在节点层中重新创建 FormData 对象以将 POST 转发到 Java 服务。
我继续收到错误消息 "Connection terminated parsing multipart data" 或者根本没有来自 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);
});
});
您可以直接将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);
});
});
对于面临"FileUploadException: the request was rejected because no multipart boundary was found"
的人来说,这是你需要做的。
https://github.com/axios/axios/issues/1006
这解决了我的问题。它不是 axios 特定的,我们只需要转发发送请求时计算的 formData headers。
对于multipart/form-data,边界是根据文件内容计算的。浏览器会自动执行此操作。但是在 node.js 中,我们需要明确转发这些。感谢 form-data
npm package 这些都为你完成了。
这是我在 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);
});