使用 Express 将上传的文件作为流获取
Get uploaded file as stream using Express
现在,我正在尝试制作一个API,它的功能之一是获取文件并将其上传到另一个网站,有点像通过[=31=上传文件。 ] 作为某种 "proxy".
我要将文件发送到的网站需要额外的步骤才能工作(即在另一个请求中发送目的地),我想让我的 API 在一个请求中全部完成,而那个请求已经有了所有需要的细节。
我已经完成了目的地请求,但我很难找到如何 "pipe" 将用户上传到我发送到网站的请求中。 request-promise
在上传文件时将文件流作为输入,因此我希望将来自用户的上传通过管道传输到请求。这样我就不必使用任何磁盘 space 来临时保存文件,特别是因为我的磁盘 space 非常有限,而且我发送它的服务器实际上没有文件限制。
截至目前,我正在使用 express-fileupload
临时保存文件,但这最终会耗尽我分配给 space 的极小 (194 MB) 文件。我正在使用 express
v4.16.4 和 Node v12.0.0。对于请求,我使用 request-promise
v4.2.4.
这是我声明 Express 应用程序和 express-fileupload
对象的方式。
var router = express.Router({ caseSensitive: true });
app.use(router);
...
router.use(require("express-fileupload")({
useTempFiles : true,
tempFileDir : ".data/temp"
}));
这是我用来将文件放入网站的方法:
if (req.body.id === undefined || req.files.file === undefined)
return new APIError(400);
if (!Object.keys(JSON.parse(fs.read(".data/master_list_of_possible_values_for_that_variable.json"))).includes(req.body.id))
return new APIError("400-ID");
var session_flag = await(session.executeRequest({
method: "POST",
uri: Constants.URL.upload.session,
form: {
id: req.body.id
}
})
.then(r => {return r;})
.catch(e => { return e; }));
if (session_flag instanceof Error)
throw session_flag;
var upload = await(session.executeRequest({
method: "POST",
uri: Constants.URL.upload.fileEndpoint,
formData: {
file: {
value: fs.createReadStream(req.files.file.tempFilePath),
options: {
filename: req.files.file.name,
contentType: req.files.file.mimetype
}
}
}
})
.then(r => {return r;})
.catch(e => { return e; }));
if (upload instanceof Error)
throw upload;
return { success: true };
我建议你做的是:
- 更改您的端点,以便您在 URL 中发送
id
,这样您就不需要阅读整个正文来发出第一个请求
- 将请求直接传送到第三方端点
const request = require('request'); // streaming works better with request
const rp = require('request-promise');
const { once } = require('events');
// Make sure you don't have any body parser enable for this request
router.post('/:id', async(req, res) => {
try {
// issue first request
await rp({
method: "POST",
uri: Constants.URL.upload.session,
form: {
id: req.body.id
}
})
// pipe request
const upload = req.pipe(request({
method: "POST",
uri: Constants.URL.upload.fileEndpoint,
headers: req.headers // Send Same Content-Type, Length and so on
}))
// will throw on 'error'
await once(upload, 'response')
// check status code if you want
const success = upload.response.statusCode === 200;
return res.json({ success })
} catch(e) {
res.status(500)
.send('error')
}
});
这样做,您不需要将它存储在临时文件中,因为您将它直接通过管道传输到第三方端点。
现在,我正在尝试制作一个API,它的功能之一是获取文件并将其上传到另一个网站,有点像通过[=31=上传文件。 ] 作为某种 "proxy".
我要将文件发送到的网站需要额外的步骤才能工作(即在另一个请求中发送目的地),我想让我的 API 在一个请求中全部完成,而那个请求已经有了所有需要的细节。
我已经完成了目的地请求,但我很难找到如何 "pipe" 将用户上传到我发送到网站的请求中。 request-promise
在上传文件时将文件流作为输入,因此我希望将来自用户的上传通过管道传输到请求。这样我就不必使用任何磁盘 space 来临时保存文件,特别是因为我的磁盘 space 非常有限,而且我发送它的服务器实际上没有文件限制。
截至目前,我正在使用 express-fileupload
临时保存文件,但这最终会耗尽我分配给 space 的极小 (194 MB) 文件。我正在使用 express
v4.16.4 和 Node v12.0.0。对于请求,我使用 request-promise
v4.2.4.
这是我声明 Express 应用程序和 express-fileupload
对象的方式。
var router = express.Router({ caseSensitive: true });
app.use(router);
...
router.use(require("express-fileupload")({
useTempFiles : true,
tempFileDir : ".data/temp"
}));
这是我用来将文件放入网站的方法:
if (req.body.id === undefined || req.files.file === undefined)
return new APIError(400);
if (!Object.keys(JSON.parse(fs.read(".data/master_list_of_possible_values_for_that_variable.json"))).includes(req.body.id))
return new APIError("400-ID");
var session_flag = await(session.executeRequest({
method: "POST",
uri: Constants.URL.upload.session,
form: {
id: req.body.id
}
})
.then(r => {return r;})
.catch(e => { return e; }));
if (session_flag instanceof Error)
throw session_flag;
var upload = await(session.executeRequest({
method: "POST",
uri: Constants.URL.upload.fileEndpoint,
formData: {
file: {
value: fs.createReadStream(req.files.file.tempFilePath),
options: {
filename: req.files.file.name,
contentType: req.files.file.mimetype
}
}
}
})
.then(r => {return r;})
.catch(e => { return e; }));
if (upload instanceof Error)
throw upload;
return { success: true };
我建议你做的是:
- 更改您的端点,以便您在 URL 中发送
id
,这样您就不需要阅读整个正文来发出第一个请求 - 将请求直接传送到第三方端点
const request = require('request'); // streaming works better with request
const rp = require('request-promise');
const { once } = require('events');
// Make sure you don't have any body parser enable for this request
router.post('/:id', async(req, res) => {
try {
// issue first request
await rp({
method: "POST",
uri: Constants.URL.upload.session,
form: {
id: req.body.id
}
})
// pipe request
const upload = req.pipe(request({
method: "POST",
uri: Constants.URL.upload.fileEndpoint,
headers: req.headers // Send Same Content-Type, Length and so on
}))
// will throw on 'error'
await once(upload, 'response')
// check status code if you want
const success = upload.response.statusCode === 200;
return res.json({ success })
} catch(e) {
res.status(500)
.send('error')
}
});
这样做,您不需要将它存储在临时文件中,因为您将它直接通过管道传输到第三方端点。