首页 > 解决方案 > 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 的访问权限。

谢谢

标签: node.jsfirebasegoogle-cloud-firestorefirebase-storagefirebase-security

解决方案


当您使用 Firebase 时,我建议您从而firebase-admin不是@google-cloud/storage直接初始化存储桶。这将整理权限,以便跳过安全规则。

在您的代码中,您还错误地混合了回调和async/ awaitAPI。由于此代码在 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') }

推荐阅读