Firebase云函数(TypeScript)文件上传遇form.parse阻塞问题排查
Firebase云函数文件上传超时,form.parse回调未执行
我尝试通过以下curl命令上传文件到Firebase云函数做后续处理,但执行后出现超时问题,form.parse的回调函数始终未触发,日志仅输出到进度0/4720 bytes就停止了。
上传用curl命令
curl --location 'http://127.0.0.1:5001/{PROJECT_ID}/us-central1/fileProcess' \ --form 'file=@"/Users/kishan/Downloads/C8tjkue6Ao.pdf"'
云函数代码(Node.js TypeScript)
import * as express from "express"; import * as admin from "firebase-admin"; import * as functions from "firebase-functions/v1"; import {Fields, Files, IncomingForm} from "formidable"; if (!admin.apps.length) { admin.initializeApp(); } const app = express(); app.use(express.json({limit: "50mb"})); app.use(express.urlencoded({extended: false, limit: "50mb"})); app.post("/", (req: express.Request, res: express.Response): void => { console.log("[INFO] Received request:", req.method); console.log("[DEBUG] Request Headers:", req.headers); const form = new IncomingForm({ keepExtensions: true, multiples: true, uploadDir: '/tmp' // 显式设置上传目录 }); // 进度跟踪 form.on('progress', (bytesReceived, bytesExpected) => { console.log(`[DEBUG] Progress: ${bytesReceived}/${bytesExpected} bytes`); }); // 错误处理 form.on('error', (err) => { console.error('[ERROR] Form error:', err); res.status(500).send({message: 'Error processing form'}); }); // 文件接收事件 form.on('file', (name, file) => { console.log('[DEBUG] Received file:', name, file.originalFilename); }); try { form.parse(req, (err: Error | null, fields: Fields, files: Files): void => { console.log("[DEBUG] Inside form.parse callback."); if (err) { console.error("[ERROR] Failed to parse form:", err); res.status(400).send({message: "Error parsing form data"}); return; } if (!files || !files.file) { console.error("[ERROR] File is required"); res.status(400).send({message: "File is required"}); return; } const fileData = Array.isArray(files.file) ? files.file[0] : files.file; if (!fileData.originalFilename) { console.error("[ERROR] File has no original filename"); res.status(400).send({message: "Invalid file data"}); return; } console.log("[INFO] Uploaded file name:", fileData.originalFilename); res.status(200).send({ message: "File uploaded successfully", fileName: fileData.originalFilename, }); console.log("[SUCCESS] File handled successfully"); }); } catch (error) { console.error("[ERROR] Exception in form parsing:", error); res.status(500).send({message: "Internal server error"}); } }); export const fileProcess = functions .runWith({ timeoutSeconds: 540, memory: '1GB' // 增加内存分配 }) .https.onRequest(app);
日志输出
[INFO] Received request: POST [DEBUG] Request Headers: { 'user-agent': 'PostmanRuntime/7.43.0', accept: '*/*', 'postman-token': '36ff596e-6822-4f80-b628-7da73efcbea1', host: '127.0.0.1:5001', 'accept-encoding': 'gzip, deflate, br', connection: 'keep-alive', 'content-type': 'multipart/form-data; boundary=--------------------------430674860192243674092838', 'content-length': '4720' } [DEBUG] Progress: 0/4720 bytes
问题原因
你给Express添加了express.json()和express.urlencoded()中间件,这两个中间件会提前尝试解析请求体,导致formidable无法读取原始的multipart请求流,进而卡住无法触发parse回调。
解决方法
- 直接移除冲突中间件:如果这个云函数只处理文件上传请求,删掉
app.use(express.json(...))和app.use(express.urlencoded(...))即可,formidable需要直接处理原始请求数据。 - 针对路由跳过中间件:如果其他路由需要这两个中间件,给上传路由单独跳过:
// 全局中间件,排除上传路由 app.use((req, res, next) => { if (req.path === '/' && req.method === 'POST') { return next(); } express.json({limit: "50mb"})(req, res, next); }); app.use((req, res, next) => { if (req.path === '/' && req.method === 'POST') { return next(); } express.urlencoded({extended: false, limit: "50mb"})(req, res, next); }); - 检查formidable版本:确保使用最新稳定版,避免版本兼容性问题。
内容的提问来源于stack exchange,提问作者Kishan Barmawala
相关产品推荐
相关产品推荐

