如何在 Cloud Functions for Firebase 上使用 express 执行 HTTP 文件上传(multer,busboy) [英] How to perform an HTTP file upload using express on Cloud Functions for Firebase (multer, busboy)

查看:14
本文介绍了如何在 Cloud Functions for Firebase 上使用 express 执行 HTTP 文件上传(multer,busboy)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将文件上传到 Cloud Functions,使用 Express 在那里处理请求,但我没有成功.我创建了一个在本地工作的版本:

I am trying to upload a file to Cloud Functions, using Express to handle requests there, but i am not succeeding. I created a version that works locally:

服务器端 js

const express = require('express');
const cors = require('cors');
const fileUpload = require('express-fileupload');

const app = express();
app.use(fileUpload());
app.use(cors());

app.post('/upload', (req, res) => {
    res.send('files: ' + Object.keys(req.files).join(', '));
});

客户端 js

const formData = new FormData();
Array.from(this.$refs.fileSelect.files).forEach((file, index) => {
    formData.append('sample' + index, file, 'sample');
});

axios.post(
    url,
    formData, 
    {
        headers: { 'Content-Type': 'multipart/form-data' },
    }
);

此完全相同的代码在部署到未定义 req.files 的 Cloud Functions 时似乎会中断.有谁知道这里发生了什么?

This exact same code seems to break when deployed to Cloud Functions, where req.files is undefined. Does anyone have any idea what is happening here?

编辑我也尝试过使用 multer,它在本地运行良好,但是一旦上传到 Cloud Functions,我得到了一个空数组(相同的客户端代码):

EDIT I also had a go at using multer, which worked fine locally, but once uploaded to Cloud Functions, this got me an empty array (same clientside code):

const app = express();
const upload = multer();
app.use(cors());

app.post('/upload', upload.any(), (req, res) => {
    res.send(JSON.stringify(req.files));
});

推荐答案

触发此问题的 Cloud Functions 设置确实发生了重大变化.它与应用于所有用于提供 HTTPS 功能的 Express 应用程序(包括默认应用程序)的中间件的工作方式有关.基本上,Cloud Functions 将解析请求的主体并决定如何处理它,将主体的原始内容留在 req.rawBody 的 Buffer 中.您可以使用它来直接解析您的多部分内容,但您不能使用中间件(如 multer)来解析.

There was indeed a breaking change in the Cloud Functions setup that triggered this issue. It has to do with the way the middleware works that gets applied to all Express apps (including the default app) used to serve HTTPS functions. Basically, Cloud Functions will parse the body of the request and decide what to do with it, leaving the raw contents of the body in a Buffer in req.rawBody. You can use this to directly parse your multipart content, but you can't do it with middleware (like multer).

相反,您可以使用名为 busboy 的模块直接处理原始正文内容.它可以接受 rawBody 缓冲区并用它找到的文件给你回电.这是一些示例代码,它将迭代所有上传的内容,将它们保存为文件,然后删除它们.你显然想做一些更有用的事情.

Instead, you can use a module called busboy to deal with the raw body content directly. It can accept the rawBody buffer and will call you back with the files it found. Here is some sample code that will iterate all the uploaded content, save them as files, then delete them. You'll obviously want to do something more useful.

const path = require('path');
const os = require('os');
const fs = require('fs');
const Busboy = require('busboy');

exports.upload = functions.https.onRequest((req, res) => {
    if (req.method === 'POST') {
        const busboy = new Busboy({ headers: req.headers });
        // This object will accumulate all the uploaded files, keyed by their name
        const uploads = {}

        // This callback will be invoked for each file uploaded
        busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
            console.log(`File [${fieldname}] filename: ${filename}, encoding: ${encoding}, mimetype: ${mimetype}`);
            // Note that os.tmpdir() is an in-memory file system, so should only 
            // be used for files small enough to fit in memory.
            const filepath = path.join(os.tmpdir(), fieldname);
            uploads[fieldname] = { file: filepath }
            console.log(`Saving '${fieldname}' to ${filepath}`);
            file.pipe(fs.createWriteStream(filepath));
        });

        // This callback will be invoked after all uploaded files are saved.
        busboy.on('finish', () => {
            for (const name in uploads) {
                const upload = uploads[name];
                const file = upload.file;
                res.write(`${file}
`);
                fs.unlinkSync(file);
            }
            res.end();
        });

        // The raw bytes of the upload will be in req.rawBody.  Send it to busboy, and get
        // a callback when it's finished.
        busboy.end(req.rawBody);
    } else {
        // Client error - only support POST
        res.status(405).end();
    }
})

请记住,保存到临时空间的文件会占用内存,因此它们的总大小应限制在 10MB 以内.对于较大的文件,您应该将它们上传到 Cloud Storage 并使用存储触发器对其进行处理.

Bear in mind that files saved to temp space occupy memory, so their sizes should be limited to a total of 10MB. For larger files, you should upload those to Cloud Storage and process them with a storage trigger.

另外请记住,Cloud Functions 添加的中间件的默认选择当前并未通过 firebase serve 添加到本地模拟器.因此,在这种情况下,此示例将不起作用(rawBody 将不可用).

Also bear in mind that the default selection of middleware added by Cloud Functions is not currently added to the local emulator via firebase serve. So this sample will not work (rawBody won't be available) in that case.

团队正在努力更新文档,以便更清楚地了解与标准 Express 应用不同的 HTTPS 请求期间发生的一切.

The team is working on updating the documentation to be more clear about what all happens during HTTPS requests that's different than a standard Express app.

这篇关于如何在 Cloud Functions for Firebase 上使用 express 执行 HTTP 文件上传(multer,busboy)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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