本文介绍了如何写入具有从Firestore触发的Firebase云功能的云存储桶?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

为了确保它尽可能干净和隔离,我创建了一个新的测试项目,除了这些步骤外,其中​​没有任何其他内容.

To make sure this is as clean and isolated as possible, I created a new test project with nothing in it other than these steps.

然后,我在控制台中启用了云Firestore.我创建了一个名为"blarg"的新集合(名字叫eh!).我向其中添加了一个文档,并使用了自动编号,然后添加了一个带有字符串dumpty的名为"humpty"的字段.在控制台中看起来像这样:

I then enabled cloud firestore in the console. I created a new collection called "blarg" (great name, eh!). I added a document to it, and used the auto-id, then added a field named "humpty" with the string dumpty. It looks like this in the console:

我在firebase控制台的storage部分中创建了一个名为signatures的目录.我想在下面的函数触发时将文件写入此目录.

I created a directory called signatures in the storage section of the firebase console. I want to write a file into this directory when my function (below) triggers.

然后,我使用以下代码添加了一个云功能.它在功能部分正确显示(我假设),其名称为testItOut并触发了/blarg/{eventId}的事件document.update.:

I then added a cloud function with the following code. It shows up (I assume) correctly in the functions section, with the name testItOut and triggering on the event document.update for /blarg/{eventId}.:

const functions = require('firebase-functions');
const os = require('os');
const fs = require('fs');
const path = require('path');
require('firebase-admin').initializeApp();

exports.testItOut = functions.firestore
    .document('blarg/{docId}')
    .onUpdate((change, context) => {
    console.log( "Inside #testItOut" );
    const projectId = 'testing-60477';
    const Storage = require('@google-cloud/storage');
    const storage = new Storage({
        projectId,
    });
    let bucketName = 'signatures';
    let fileName = 'temp.txt';
    const tempFilePath = path.join(os.tmpdir(), fileName);
    console.log( `Writing out to ${tempFilePath}` );
    fs.writeFileSync(tempFilePath, "something!" );

    return storage
        .bucket( bucketName )
        .upload( tempFilePath )
        .then( () => fs.unlinkSync(tempFilePath) )
        .catch(err => console.error('ERROR inside upload: ', err) );
    });

package.json看起来像这样:

The package.json looks like this:

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "lint": "eslint .",
    "serve": "firebase serve --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "dependencies": {
    "@google-cloud/storage": "^1.7.0",
    "firebase-admin": "~5.12.1",
    "firebase-functions": "^1.0.3"
  },
  "devDependencies": {
    "eslint": "^4.12.0",
    "eslint-plugin-promise": "^3.6.0"
  },
  "private": true
}

如果更改键"humpty"的值,则会看到函数调用.但是,我在日志中看到错误.

If I change the value of the key "humpty" I see the function invocation. But, I get the error inside the logs.

ERROR inside upload:  { ApiError: [email protected] does not have storage.objects.create access to signatures/temp.txt.
    at Object.parseHttpRespBody (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:193:30)
    at Object.handleResp (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:131:18)
...

我认为这是尽可能简单的方法.我究竟做错了什么?我以为调用initializeApp()赋予了我的功能权限,可以自动将其写入该帐户的存储桶中?

This is as simple as it can get, I'd assume. What am I doing wrong? I thought calling initializeApp() gave my function rights to write to the storage bucket for the account automatically?

我看到的唯一奇怪的错误是未设置计费.我认为只有在使用外部API时才有必要. Google Storage是外部API"吗?日志消息并不表示这是问题所在.

The only strange error I see is that billing is not setup. I thought this was necessary only if you use external APIs. Is Google Storage an "external API?" The log message does not indicate that's the issue.

推荐答案

问题是我错误地认为对bucket的调用是在存储桶中设置子目录.代替bucket('signatures'),我应该像bucket()那样进行空调用,然后为upload调用提供一个options参数(例如{ destination: '/signatures/temp.txt' }):

The issue was that I mistakenly thought the call to bucket was to set the subdirectory inside the bucket. Instead of bucket('signatures') I should have made it an empty call like bucket() and then provided an options parameter (like { destination: '/signatures/temp.txt' }) for the upload call:

const functions = require('firebase-functions');
const os = require('os');
const fs = require('fs');
const path = require('path');
const admin = require('firebase-admin');
admin.initializeApp();

exports.testItOut = functions.firestore
    .document('blarg/{docId}')
    .onUpdate((change, context) => {
    console.log( "Inside #testItOut" );
    const storage = admin.storage()
    let fileName = 'temp.txt';
    let destination = '/signatures/temp.txt';
    const tempFilePath = path.join(os.tmpdir(), fileName);
    console.log( `Writing out to ${tempFilePath}` );
    fs.writeFileSync(tempFilePath, "something!" );

    return storage
        .bucket()
        .upload( tempFilePath, { destination } )
        .then( () => fs.unlinkSync(tempFilePath) )
        .catch(err => console.error('ERROR inside upload: ', err) );
    });

我很困惑,因为我在Firebase文档中看到了许多调用bucket("albums")的示例(例如: https://cloud.google.com/nodejs/docs/reference/storage/1.6.x/Bucket#getFiles ),并认为这意味着存储桶可用于为上传设置子目录.现在,对我来说,区别很明显,但是我被抛弃了,因为对桶的调用不像我在Firebase存储控制台中看到的那样bucketname-12345.appspot.com.

I got confused because I saw lots of examples in firebase docs where there are calls to bucket("albums") (like this: https://cloud.google.com/nodejs/docs/reference/storage/1.6.x/Bucket#getFiles) and assumed this meant the bucket can be used to set a subdirectory for uploads. It's obvious to me now the difference, but I was thrown off because the calls to bucket did not look like bucketname-12345.appspot.com as I see in the firebase storage console.

这篇关于如何写入具有从Firestore触发的Firebase云功能的云存储桶?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 16:12