node.js - Firebase 存储文件下载在一段时间后停止工作
问题描述
我在将文件上传到 Firebase 时设置了一个简单的触发器。它读取上传的文件,处理它并将结果保存到数据库。它工作了一段时间,之后它崩溃并停止工作。通常上传功能会有所帮助。有人知道可能是什么原因吗?我是失忆了还是……?
这是代码:
const {Storage} = require('@google-cloud/storage');
const path = require('path');
const storage = new Storage();
exports.processLogs = functions
.region('europe-west1')
.storage
.object()
.onFinalize(async (object) => {
const filename = path.basename(object.name);
const bucket = storage.bucket(object.bucket);
try {
await bucket.file(filename).download(async (err, contents) => {
if (err) {
console.log('error', err);
return null
}
//Proces file and store into db
// (...)
bucket.file(filename).delete();
});
} catch(e){
console.log('error',e)
}
});
我得到的错误是:
匿名调用者没有 storage.objects.get 对 project-name.appspot.com/CrTwBuyNR2-log-2020-1-16-12-18.csv 的访问权限。
谢谢
解决方案
当您使用 Firebase 时,我建议您从而firebase-admin
不是@google-cloud/storage
直接初始化存储桶。这将整理权限,以便跳过安全规则。
在您的代码中,您还错误地混合了回调和async
/ await
API。由于此代码在 Cloud Function 中运行,因此我建议仅使用 Promises 和async
/ await
。
下面的代码是经过以下更改的重写:
- 代码已被拆分为逻辑块
- 不使用回调 API(请参阅
File#download
) - 每个块将分别记录和抛出错误,以便于调试
- 单行日志消息(即没有堆栈跟踪)
- 将完整的错误日志记录留给 Cloud Functions(使查找错误运行更容易)
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp();
exports.processLogs = functions.region('europe-west1').storage.object()
.onFinalize(async (object) => {
const bucketRef = admin.storage().bucket(object.bucket);
const fileRef = bucketRef.file(object.name);
console.log('Processing "' + object.id + '"...');
// 1) DOWNLOAD
let [contents] = await fileRef.download()
.catch((err) => {
console.log('DOWNLOAD FAILED: ', (err.code ? err.code + ': ' : '') + err.message);
throw err;
});
// 2) PARSE
let dataToUpload = {};
try {
// Transform file contents
dataToUpload = JSON.parse(contents);
} catch (err) {
console.log('PARSE FAILED: ', (err.code ? err.code + ': ' : '') + err.message);
throw err;
}
// 3) DATABASE SET
const dbRef = admin.database().ref('path/to/data');
await dbRef.set(dataToUpload)
.catch((err) => {
console.log('DATABASE SET FAILED: ', (err.code ? err.code + ': ' : '') + err.message);
throw err;
});
// 4) CLEANUP
await fileRef.delete()
.catch((err) => {
console.log('CLEANUP FAILED: ', (err.code ? err.code + ': ' : '') + err.message);
throw err;
});
// 5) LOG SUCCESS
console.log('SUCCEEDED');
});
如果需要,也可以将上面的日志消息捆绑到辅助函数中:
function logAndRethrowError(err, name) {
console.log((name || 'ERROR') + ': ', ((err.code ? err.code + ': ' : '') + err.message) || err);
throw err;
}
// Usage:
let [contents] = await fileRef.download()
.catch(err => logAndRethrowError(err, 'DOWNLOAD FAILED'));
try {
// ...
} catch (err) { logAndRethrowError(err, 'PARSE FAILED') }
推荐阅读
- jmeter - 在JMeter中随机提取JSR223后处理器中的对应值
- appium - 如何确保在杀死 Appium 后释放 UIAutmator2 的端口 8200..8299?
- karate - 如何在 karate-dsl 中参数化外部保存的 sql 查询
- angular - 是否可以有多个采摘运算符(rxjs)
- sql - 一个查询/ AdventureWorks2017 任务中的 COUNT 和 MAX/MIN 和(HAVING?)
- php - 使用php创建两个三角形
- pytorch - 如何在 PyTorch 中将张量大小从 [a, b] 转换为 [a, b, k]
- c# - 访问从 SQLite 数据库返回的字符串任务的字段会出错
- linux - 使用 objdump 程序集删除地址列并添加标签
- azure-devops - Azure devops CI CD 部署中的访问被拒绝错误