node.jsfile-uploadgoogle-cloud-functions

Uploading files using Google Function Framework


I can't get file uploads to work with FunctionFramework when using Express.

I've created an example repo: https://github.com/Boardtale/FunctionFrameworkAndUploadingFiles/blob/master/index.js.

I've tried using Multer, Formidable, Busboy, and even a native approach. All of them fail when using FunctionFramework but work perfectly fine when I call Express directly and listen on a port.

It seems like something is happening behind the scenes that I can't figure out. I’ve also tried adding different body parsers, but nothing helps.

So here's the results I get for specific libs.
Multer: req.file is undefined
Formiddable: does not enter form.parse
Native: does not enter req.on('end'
Busyboy:

Error parsing the file upload: Error: Unexpected end of form at Multipart._final (W:\workspace\playground\node_modules\busboy\lib\types\multipart.js:588:17) at prefinish (node:internal/streams/writable:914:14) at finishMaybe (node:internal/streams/writable:928:5) at Writable.end (node:internal/streams/writable:843:5) at onend (node:internal/streams/readable:946:10) at process.processTicksAndRejections (node:internal/process/task_queues:77:11) Exception from a finished function: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

Ofc file is sent with Content-Type: multipart/form-data; boundary=<calculated when request is sent>


Solution

  • As mentioned in the similar thread by @samthecodingman

    Firebase Functions are constructed upon the functions-framework-nodejs package (or, alternatively, an in-house version of the same code), which parses the body before your code ever runs. This behavior is recorded in this document.

    This indicates that the request's body stream has already been exhausted when you attempt to feed it to Busboy, which is why you are seeing the "Unexpected end of form" error message. You must use the rawBody property that the framework added to the request in order to access and execute the original request content.

    You can also refer to this stackoverflow thread