问题描述
为了确保它尽可能干净和隔离,我创建了一个新的测试项目,除了这些步骤外,其中没有任何其他内容.
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云功能的云存储桶?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!