Google Cloud Function-为什么存储桶总是返回空文件数组?

时间:2019-07-29 21:56:10

标签: javascript firebase google-cloud-functions google-cloud-storage firebase-storage

我正在尝试访问存储在Firebase存储器中的文件,以将它们的列表返回到我的APK。我做了一个云功能,即使一切似乎都已解决,该功能也无法正常工作。

index.js

const {Storage} = require('@google-cloud/storage');

const functions = require('firebase-functions');

const images = require('./images.js');

const storage = new Storage({
    projectId: '<my_id>',
    keyFilename: './key.json',
});

const bucket = storage.bucket('<my_bucket>')

exports.getImages = functions.https.onRequest((request, response) => {
    images.getImages(bucket).then(urls => response.send(urls))
})

images.js

module.exports = {
    getImages
}

const query = {
    directory: '/images'
};

async function getImages(bucket) {
    return bucket.getFiles(query).then(files => {
        console.log(files)
        getUrls(files).then(urls => console.log(urls))
            .catch(() => console.error('URLs failure'));
    }).catch(() => console.error('Files failure'));
}

function getUrls(files) {
    const promises = []
    files.forEach(file => promises.push(file.getDownloadURL()))
    return Promise.all(promises);
}

我的Key.json位于我的功能文件夹内

Key.json

{
  "type": "service_account",
  "project_id": "…”,
  "private_key_id": “…”,
  "private_key": "-----BEGIN PRIVATE KEY——…”,
  "client_email": “…”,
  "client_id": “…”,
  "auth_uri": “…”,
  "token_uri": “…”,
  "auth_provider_x509_cert_url": “…”,
  "client_x509_cert_url": “…”
}

存储规则

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if true
    }
  }
}

执行getImages()函数输出为:

console.log(files): [ [] ]
console.error('Files failure'): Files failure

请问我在做什么错了?

2 个答案:

答案 0 :(得分:2)

我遇到的第一个也是主要的问题是与我的Google Cloud Service连接,这意味着:

  1. 我从Firebase管理员生成了一个全新的私钥

Firebase project Project settings Generate new key

  1. 下载的文件并以我的新Key.json

  2. 然后是最棘手的部分。根据{{​​3}}的文档

  

您可以将Admin SDK返回的存储桶引用与正式的Google Cloud Storage客户端库一起使用,以上传,下载和修改与Firebase项目关联的存储桶中的内容。请注意,使用Firebase Admin SDK时不必认证Google Cloud Storage库。 Admin SDK返回的存储桶引用已通过用于初始化Firebase应用程序的凭据进行了身份验证。

这意味着,如果您在本地运行服务(npm run shell),则需要实例化firebase-admin

var serviceAccount = require("./key.json");
var admin = require("firebase-admin");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://<my_project>.firebaseio.com"
});

然后致电

const bucket = admin.storage().bucket('<my_bucket>.appspot.com')

您将准备访问您的文件。直接通过部署或通过Google访问google函数时,则不需要进行admin初始化或密钥本身(例如问题中第一个公开的index.js)进行访问,代码只变成类似

的东西
const {Storage} = require('@google-cloud/storage');
...
const storage = new Storage({
    projectId: '<my_id>',
});

const bucket = storage.bucket('<my_bucket>')
...

关于Mayeru所说的话:

  

您已将目录指定为“ / images”,但应将其指定为“ images /”

"images/"可用于查询prefix参数,而不是directorycloud console示例展示了它的工作原理,就像Google文档的This一样。

以下代码进行了一些许诺调整,并为Android解析了JSON数据,它们的工作原理很吸引人。本地和远程。

index.js

var serviceAccount = require("./key.json");
const functions = require('firebase-functions');

const images = require('./images.js');

var admin = require("firebase-admin");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://<my_project>.firebaseio.com"
});

const bucket = admin.storage().bucket('<my_bucket>.appspot.com')

exports.getImages = functions.https.onRequest((request, response) => {
    images.getImages(bucket)
        .then(urls => response.status(200).send({ data: { urls } }))
        .catch(err => console.error(err));
})

images.js

module.exports = {
    getImages
}

const query = {
    directory: 'images'
};

function getImages(bucket) {
    return bucket.getFiles(query)
        .then(response => getUrls(response))
        .catch(err => console.error(err));
}

function getUrls(response) {
    const promises = []
    response.forEach( files => {
        files.forEach (file => {
            promises.push(getSignedUrl(file));
        });
    });
    return Promise.all(promises).then(result => getParsedUrls(result));
}

function getSignedUrl(file) {
    return file.getSignedUrl({
        action: 'read',
        expires: '09-01-2019'
    })
}

function getParsedUrls(result) {
    return JSON.stringify(result.map(mediaLink => createMedia(mediaLink)));
}

function createMedia(mediaLink) {
    const reference = {};
    reference.mediaLink = mediaLink[0];
    return reference;
}

这肯定会列出您存储桶中images文件夹下的所有文件,并访问它们的签名下载URL,这些URL将用Fresco之类的库呈现。最后但并非最不重要的一点是,下载URL将公开,但是要直接在其上发出GET请求,则需要调整存储桶权限。无论如何,这种“权限问题”是另一个主题,您可能还会在堆栈溢出的情况下找到如何做的事情。

答案 1 :(得分:1)

日志显示:

[[]] // this is the "files" you retrieved.
Files failure 

如您所见,您没有检索任何文件,因此为什么它无法从空数组获取URL的调用失败。

您已将目录指定为“ / images” ,但应将其指定为“ images /”

那应该能够检索正确的文件夹。

此外,nodejs lib documentation上的“文件”对象不支持函数“ getDownloadURL()”。您可能正在寻找getSignedUrl吗?