用于文件上传的 Firebase 云功能
Firebase cloud function for file upload
我有这个云功能,我写的是将文件上传到 google 云存储:
const gcs = require('@google-cloud/storage')({keyFilename:'2fe4e3d2bfdc.json'});
var filePath = file.path + "/" + file.name;
return bucket.upload(filePath, {
destination: file.name
}).catch(reason => {
console.error(reason);
});
我用formidable
解析了上传的文件,我尝试记录上传文件的属性,似乎没问题;它已上传到临时目录 '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/
但是当我尝试将文件上传到 gcs 时出现此错误:
{ Error: EACCES: permission denied, stat '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/thumb_ttttttt.jpg'
at Error (native)
errno: -13,
code: 'EACCES',
syscall: 'stat',
path: '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/thumb_ttttttt.jpg' }
我正在使用这个 html 表单上传文件:
<!DOCTYPE html>
<html>
<body>
<form action="https://us-central1-appname.cloudfunctions.net/uploadFile" method="post" enctype="multipart/form-data">
Select image to upload:
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="Upload Image" name="submit">
</form>
</body>
</html>
我通过 下载 文件到 tmp
来管理这个。
您将需要:
const mkdirp = require('mkdirp-promise');
然后,里面onChange
。我这样创建了 tempLocalDir
:
const LOCAL_TMP_FOLDER = '/tmp/';
const fileDir = (the name of the file); //whatever method you choose to do this
const tempLocalDir = `${LOCAL_TMP_FOLDER}${fileDir}`;
然后我使用 mkdirp 制作临时目录
return mkdirp(tempLocalDir).then(() => {
// Then Download file from bucket.
const bucket = gcs.bucket(object.bucket);
return bucket.file(filePath).download({
destination: tempLocalFile
}).then(() => {
console.log('The file has been downloaded to', tempLocalFile);
//Here I have some code that converts images then returns the converted image
//Then I use
return bucket.upload((the converted image), {
destination: (a file path in your database)
}).then(() => {
console.log('JPEG image uploaded to Storage at', filePath);
})//You can perform more actions of end the promise here
我认为我的代码实现了您试图实现的目标。我希望这有帮助;如有必要,我可以提供更多代码。
我从 Firebase 支持团队
那里得到了解决方案
所以第一件事:
var filePath = file.path + "/" + file.name;
我们不需要 file.name,因为 file.path
是文件的完整路径(包括文件名)。
所以改为:
var filePath = file.path;
其次,函数在 'form.parse(...)' 中的异步工作完成之前终止。这意味着当函数执行结束时,实际的文件上传可能仍在进行中。
解决方法是将 form.parse(...)
包装在一个 promise 中:
exports.uploadFile = functions.https.onRequest((req, res) => {
var form = new formidable.IncomingForm();
return new Promise((resolve, reject) => {
form.parse(req, function(err, fields, files) {
var file = files.fileToUpload;
if(!file){
reject("no file to upload, please choose a file.");
return;
}
console.info("about to upload file as a json: " + file.type);
var filePath = file.path;
console.log('File path: ' + filePath);
var bucket = gcs.bucket('bucket-name');
return bucket.upload(filePath, {
destination: file.name
}).then(() => {
resolve(); // Whole thing completed successfully.
}).catch((err) => {
reject('Failed to upload: ' + JSON.stringify(err));
});
});
}).then(() => {
res.status(200).send('Yay!');
return null
}).catch(err => {
console.error('Error while parsing form: ' + err);
res.status(500).send('Error while parsing form: ' + err);
});
});
最后,您可能要考虑使用 Cloud Storage for Firebase 上传文件而不是 Cloud 函数。 Cloud Storage for Firebase 允许您直接将文件上传到它,而且效果会更好:
- 它有访问控制
- 它具有可恢复的功能 uploads/downloads(非常适合连接性差的情况)
- 它可以接受任何大小的文件而不会出现超时问题
- 如果你想在文件上传时触发一个云功能,你可以
做到这一点以及更多
我有这个云功能,我写的是将文件上传到 google 云存储:
const gcs = require('@google-cloud/storage')({keyFilename:'2fe4e3d2bfdc.json'});
var filePath = file.path + "/" + file.name;
return bucket.upload(filePath, {
destination: file.name
}).catch(reason => {
console.error(reason);
});
我用formidable
解析了上传的文件,我尝试记录上传文件的属性,似乎没问题;它已上传到临时目录 '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/
但是当我尝试将文件上传到 gcs 时出现此错误:
{ Error: EACCES: permission denied, stat '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/thumb_ttttttt.jpg'
at Error (native)
errno: -13,
code: 'EACCES',
syscall: 'stat',
path: '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/thumb_ttttttt.jpg' }
我正在使用这个 html 表单上传文件:
<!DOCTYPE html>
<html>
<body>
<form action="https://us-central1-appname.cloudfunctions.net/uploadFile" method="post" enctype="multipart/form-data">
Select image to upload:
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="Upload Image" name="submit">
</form>
</body>
</html>
我通过 下载 文件到 tmp
来管理这个。
您将需要:
const mkdirp = require('mkdirp-promise');
然后,里面onChange
。我这样创建了 tempLocalDir
:
const LOCAL_TMP_FOLDER = '/tmp/';
const fileDir = (the name of the file); //whatever method you choose to do this
const tempLocalDir = `${LOCAL_TMP_FOLDER}${fileDir}`;
然后我使用 mkdirp 制作临时目录
return mkdirp(tempLocalDir).then(() => {
// Then Download file from bucket.
const bucket = gcs.bucket(object.bucket);
return bucket.file(filePath).download({
destination: tempLocalFile
}).then(() => {
console.log('The file has been downloaded to', tempLocalFile);
//Here I have some code that converts images then returns the converted image
//Then I use
return bucket.upload((the converted image), {
destination: (a file path in your database)
}).then(() => {
console.log('JPEG image uploaded to Storage at', filePath);
})//You can perform more actions of end the promise here
我认为我的代码实现了您试图实现的目标。我希望这有帮助;如有必要,我可以提供更多代码。
我从 Firebase 支持团队
那里得到了解决方案所以第一件事:
var filePath = file.path + "/" + file.name;
我们不需要 file.name,因为 file.path
是文件的完整路径(包括文件名)。
所以改为:
var filePath = file.path;
其次,函数在 'form.parse(...)' 中的异步工作完成之前终止。这意味着当函数执行结束时,实际的文件上传可能仍在进行中。
解决方法是将 form.parse(...)
包装在一个 promise 中:
exports.uploadFile = functions.https.onRequest((req, res) => {
var form = new formidable.IncomingForm();
return new Promise((resolve, reject) => {
form.parse(req, function(err, fields, files) {
var file = files.fileToUpload;
if(!file){
reject("no file to upload, please choose a file.");
return;
}
console.info("about to upload file as a json: " + file.type);
var filePath = file.path;
console.log('File path: ' + filePath);
var bucket = gcs.bucket('bucket-name');
return bucket.upload(filePath, {
destination: file.name
}).then(() => {
resolve(); // Whole thing completed successfully.
}).catch((err) => {
reject('Failed to upload: ' + JSON.stringify(err));
});
});
}).then(() => {
res.status(200).send('Yay!');
return null
}).catch(err => {
console.error('Error while parsing form: ' + err);
res.status(500).send('Error while parsing form: ' + err);
});
});
最后,您可能要考虑使用 Cloud Storage for Firebase 上传文件而不是 Cloud 函数。 Cloud Storage for Firebase 允许您直接将文件上传到它,而且效果会更好:
- 它有访问控制
- 它具有可恢复的功能 uploads/downloads(非常适合连接性差的情况)
- 它可以接受任何大小的文件而不会出现超时问题
- 如果你想在文件上传时触发一个云功能,你可以 做到这一点以及更多