Busboy 文件事件未触发
Busboy file event not firing
所以,我有这个 post 请求,它过去工作正常,但是一旦我升级到节点 10,我似乎无法弄清楚为什么文件事件完全停止触发...
router.post('/uploadImage', authenticate.FBAuth, (req, res) => {
const busboy = new BusBoy({ headers: req.headers });
let imageFileName;
let imageToBeUploaded = {};
busboy.on('file', function onFile(fieldname, file, filename, encoding, mimetype) {
console.log('onFile started');
if (mimetype !== 'image/png' && mimetype !== 'image/jpeg') {
return res.status(400).json({ error: 'Unsupported file format' });
}
const imageExtension = path.extname(filename);
imageFileName = `${Math.round(Math.random() * 100000000000)}.${imageExtension}`;
console.log(imageFileName);
const filepath = path.join(os.tmpdir(), imageFileName);
console.log(filepath);
imageToBeUploaded = { filepath, mimetype };
console.log(imageToBeUploaded);
file.pipe(fs.createWriteStream(filepath));
});
busboy.on('finish', function onFinish() {
admin
.storage()
.bucket(config.storageBucket)
.upload(imageToBeUploaded.filepath, {
resumable: false,
metadata: {
metadata: {
contentType: imageToBeUploaded.mimetype
}
}
})
.then(() => {
const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`;
return db.doc(`/users/${req.user.handle}`).update({ imageUrl });
})
.then(() => {
return res.json({ message: 'Image uploaded successfully' });
})
.catch(error => {
console.error(error);
return res.status(500).json({ error: error.code });
});
});
busboy.end(req.rawBody);
});
我尝试在 onFinish 中执行 console.log(imageToBeUploaded);
,它始终是空的 object。此外,onFile 中的任何控制台日志似乎都不会打印出来。
我也尝试过不使用 authenticate.FBAuth 中间件,但这没有任何区别。
这是来自 bucket().upload()
的错误,基本上是抱怨路径无效,这是有道理的,因为 imageToBeUploaded
是空的 object,因此 imageToBeUploaded.filepath
是 undefined
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
at validateString (internal/validators.js:121:11)
at Object.basename (path.js:1156:5)
at Bucket.upload (/Users/mac/Dev/meows/server/node_modules/firebase-admin/node_modules/@google-cloud/storage/build/src/bucket.js:2493:38)
at /Users/mac/Dev/meows/server/node_modules/firebase-admin/node_modules/@google-cloud/promisify/build/src/index.js:69:28
at new Promise (<anonymous>)
at Bucket.wrapper (/Users/mac/Dev/meows/server/node_modules/firebase-admin/node_modules/@google-cloud/promisify/build/src/index.js:54:16)
at Busboy.onFinish (/Users/mac/Dev/meows/server/routes/profileRouter.js:116:14)
at Busboy.emit (events.js:315:20)
at Busboy.emit (/Users/mac/Dev/meows/server/node_modules/busboy/lib/main.js:37:33)
at /Users/mac/Dev/meows/server/node_modules/busboy/lib/types/multipart.js:304:17 {
code: 'ERR_INVALID_ARG_TYPE'
}
我正在使用 Postman 进行测试,并为 body 选择 form-data 并为输入类型选择文件。确保 Postman 处理了 Content-Type header 并将其设置为 multipart/form-data; boundary=<calculated when request is sent>
此外,这是包含 authenticate.FBAuth
的文件,以防万一
const admin = require('firebase-admin');
const db = admin.firestore();
module.exports = {
FBAuth: (req, res, next) => {
let idToken;
if (req.headers.authorization == null || !req.headers.authorization.startsWith('bearer ')) {
console.log('Unrecognized token format');
return res.status(400).json({ error: 'Unauthorized operation' });
}
else {
idToken = req.headers.authorization.split('bearer ')[1];
}
return admin.auth().verifyIdToken(idToken)
.then(decodedToken => {
req.user = decodedToken;
return db.collection('users')
.where('userId', '==', req.user.uid)
.limit(1)
.get()
.then(data => {
req.user.handle = data.docs[0].data().handle;
req.user.imageUrl = data.docs[0].data().imageUrl;
return next();
});
})
.catch(error => {
console.log('Error verifying token ', error);
return res.status(403).json(error);
});
}
}
这里是package.json
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"start": "node index.js"
},
"engines": {
"node": "10"
},
"dependencies": {
"body-parser": "^1.19.0",
"busboy": "^0.3.1",
"express": "^4.17.1",
"firebase": "^7.15.0",
"firebase-admin": "^8.6.0",
"unirest": "^0.6.0"
},
"private": true
}
我修好了
问题是代码已从云函数迁移到 docker。在云函数中,您使用 busboy.end(req.rawBody)
因为这是云函数在使用请求后存储请求的地方。但是在迁移到 docker 之后,请求被直接传递到快速路由并且 req.rawBody
永远不会被填充。解决方案是将 busboy.end(req.rawBody)
替换为 req.pipe(busboy)
所以,我有这个 post 请求,它过去工作正常,但是一旦我升级到节点 10,我似乎无法弄清楚为什么文件事件完全停止触发...
router.post('/uploadImage', authenticate.FBAuth, (req, res) => {
const busboy = new BusBoy({ headers: req.headers });
let imageFileName;
let imageToBeUploaded = {};
busboy.on('file', function onFile(fieldname, file, filename, encoding, mimetype) {
console.log('onFile started');
if (mimetype !== 'image/png' && mimetype !== 'image/jpeg') {
return res.status(400).json({ error: 'Unsupported file format' });
}
const imageExtension = path.extname(filename);
imageFileName = `${Math.round(Math.random() * 100000000000)}.${imageExtension}`;
console.log(imageFileName);
const filepath = path.join(os.tmpdir(), imageFileName);
console.log(filepath);
imageToBeUploaded = { filepath, mimetype };
console.log(imageToBeUploaded);
file.pipe(fs.createWriteStream(filepath));
});
busboy.on('finish', function onFinish() {
admin
.storage()
.bucket(config.storageBucket)
.upload(imageToBeUploaded.filepath, {
resumable: false,
metadata: {
metadata: {
contentType: imageToBeUploaded.mimetype
}
}
})
.then(() => {
const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`;
return db.doc(`/users/${req.user.handle}`).update({ imageUrl });
})
.then(() => {
return res.json({ message: 'Image uploaded successfully' });
})
.catch(error => {
console.error(error);
return res.status(500).json({ error: error.code });
});
});
busboy.end(req.rawBody);
});
我尝试在 onFinish 中执行 console.log(imageToBeUploaded);
,它始终是空的 object。此外,onFile 中的任何控制台日志似乎都不会打印出来。
我也尝试过不使用 authenticate.FBAuth 中间件,但这没有任何区别。
这是来自 bucket().upload()
的错误,基本上是抱怨路径无效,这是有道理的,因为 imageToBeUploaded
是空的 object,因此 imageToBeUploaded.filepath
是 undefined
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
at validateString (internal/validators.js:121:11)
at Object.basename (path.js:1156:5)
at Bucket.upload (/Users/mac/Dev/meows/server/node_modules/firebase-admin/node_modules/@google-cloud/storage/build/src/bucket.js:2493:38)
at /Users/mac/Dev/meows/server/node_modules/firebase-admin/node_modules/@google-cloud/promisify/build/src/index.js:69:28
at new Promise (<anonymous>)
at Bucket.wrapper (/Users/mac/Dev/meows/server/node_modules/firebase-admin/node_modules/@google-cloud/promisify/build/src/index.js:54:16)
at Busboy.onFinish (/Users/mac/Dev/meows/server/routes/profileRouter.js:116:14)
at Busboy.emit (events.js:315:20)
at Busboy.emit (/Users/mac/Dev/meows/server/node_modules/busboy/lib/main.js:37:33)
at /Users/mac/Dev/meows/server/node_modules/busboy/lib/types/multipart.js:304:17 {
code: 'ERR_INVALID_ARG_TYPE'
}
我正在使用 Postman 进行测试,并为 body 选择 form-data 并为输入类型选择文件。确保 Postman 处理了 Content-Type header 并将其设置为 multipart/form-data; boundary=<calculated when request is sent>
此外,这是包含 authenticate.FBAuth
的文件,以防万一
const admin = require('firebase-admin');
const db = admin.firestore();
module.exports = {
FBAuth: (req, res, next) => {
let idToken;
if (req.headers.authorization == null || !req.headers.authorization.startsWith('bearer ')) {
console.log('Unrecognized token format');
return res.status(400).json({ error: 'Unauthorized operation' });
}
else {
idToken = req.headers.authorization.split('bearer ')[1];
}
return admin.auth().verifyIdToken(idToken)
.then(decodedToken => {
req.user = decodedToken;
return db.collection('users')
.where('userId', '==', req.user.uid)
.limit(1)
.get()
.then(data => {
req.user.handle = data.docs[0].data().handle;
req.user.imageUrl = data.docs[0].data().imageUrl;
return next();
});
})
.catch(error => {
console.log('Error verifying token ', error);
return res.status(403).json(error);
});
}
}
这里是package.json
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"start": "node index.js"
},
"engines": {
"node": "10"
},
"dependencies": {
"body-parser": "^1.19.0",
"busboy": "^0.3.1",
"express": "^4.17.1",
"firebase": "^7.15.0",
"firebase-admin": "^8.6.0",
"unirest": "^0.6.0"
},
"private": true
}
我修好了
问题是代码已从云函数迁移到 docker。在云函数中,您使用 busboy.end(req.rawBody)
因为这是云函数在使用请求后存储请求的地方。但是在迁移到 docker 之后,请求被直接传递到快速路由并且 req.rawBody
永远不会被填充。解决方案是将 busboy.end(req.rawBody)
替换为 req.pipe(busboy)