使用 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 };

我建议你做的是:

  1. 更改您的端点,以便您在 URL 中发送 id,这样您就不需要阅读整个正文来发出第一个请求
  2. 将请求直接传送到第三方端点
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')
   }
});

这样做,您不需要将它存储在临时文件中,因为您将它直接通过管道传输到第三方端点。