微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

尝试通过 Next.js API 路由上的 admin.firestore.v1.FirestoreAdminClient 导出备份错误:无法加载默认凭据

如何解决尝试通过 Next.js API 路由上的 admin.firestore.v1.FirestoreAdminClient 导出备份错误:无法加载默认凭据

我正在尝试运行此代码来实现 Firestore 备份。

但这是我第一次将其部署到 Next.js 项目中。

我会在我的 /api/backup 端点上点击它。

const backupHandler: NextApiHandler = async (req,res) => {
  try {
  
    const admin = initializefirebaseAdmin();
    const PROJECT_ID = getProjectId();
    
    const client = new admin.firestore.v1.FirestoreAdminClient();
    const DB_NAME = client.databasePath(PROJECT_ID,'(default)');

    const TODAY = getToday();  // YYYY-MM-DD
    const hashId = generateId().slice(0,5);
    const BUCKET = `gs://${PROJECT_ID}.appspot.com`;
    const FOLDER = `firestore-backup/${TODAY}-${hashId}`;
    const FULL_PATH = `${BUCKET}/${FOLDER}`;

    await client.exportDocuments({
      name: DB_NAME,outputUriPrefix: FULL_PATH,collectionIds: [] // CAN LIST SPECIFIC COLLECTIONS
    });

    console.log(`Backup successfully exported`);
    return res.status(200).send("Ok");
    
  }
  catch(err) {
    console.log(err);
    return res.status(500).send("Server error");
  }
  
};

这是initializefirebaseAdmin()函数

type FirebaseAdmin = typeof import("firebase-admin/lib/firebase-namespace")

const getServiceAccount = () : admin.ServiceAccount => {
  if (process.env.VERCEL_ENV === "production"
  ||  process.env.VERCEL_GIT_COMMIT_REF === "staging")  {
    return SERVICE_ACCOUNT.PROD;
  }
  else return SERVICE_ACCOUNT.TEST;
};

export const initializefirebaseAdmin = (): FirebaseAdmin => {
  const account = getServiceAccount();  // THIS GETS THE SERVICE ACOUNT (VIA THE DOWNLOADED .json FILE)
  const PROJECT_ID = getProjectId();
  if (!admin.apps.length) {
    admin.initializeApp({
      credential: admin.credential.cert(account),databaseURL: `https://${PROJECT_ID}.firebaseio.com`  // I TRIED WITH AND WITHOUT THIS LINE: SAME RESULT
    });
  }
  return admin;
};

这是我得到的错误

错误:无法加载认凭据。浏览到 https://cloud.google.com/docs/authentication/getting-started 了解更多信息。 在 GoogleAuth.getApplicationDefaultAsync (/var/task/node_modules/google-auth-library/build/src/auth/googleauth.js:173:19)

enter image description here

起初我只是使用 credential 属性。然后我添加databaseURL 以查看它是否可以解决问题,但结果仍然相同。

我想我正确地初始化了 firebase-admin。不确定这里出了什么问题。


更新: 刚刚发现这个完全相同的代码在我的本地环境(开发中)上运行良好,但在我部署它时在我的 Next.js Node.js 环境中不起作用。可能出什么问题了?

解决方法

在地狱里待了几天后,才发现我做错了什么。

我使用 new admin.firestore.v1.FirestoreAdminClient(); 是因为 firebase-admin 本身不会公开任何方法让我们访问 exportDocuments() 功能。

但事实是,当您像这样实例化 FirestoreAdminClient 时,它无法访问您在 admin.initializeApp({credentials}) 上使用的凭据。

因此您需要通过执行以下操作将凭据传递给客户端:

import * as admin from "firebase-admin";  // OR IMPORT IT FROM SOME SINGLETON initializeFirebaseAdmin FUNCTION
import { NextApiHandler } from "next";
import SERVICE_ACCOUNT from "some-path/serviceAccount.json";

interface CredentialBody { // COPIED THIS FROM google-auth-library > auth > credentials
  client_email?: string;
  private_key?: string;
}

const backupHandler: NextApiHandler = async (req,res) => {

  const client = new admin.firestore.v1.FirestoreAdminClient({
    credentials: SERVICE_ACCOUNT as CredentialBody    // <<<<<< THIS IS THE IMPORTANT PART
  });

  const PROJECT_ID = getProjectId();
  const DB_NAME = client.databasePath(PROJECT_ID,"(default)");

  const TODAY = getToday();  // YYYY-MM-DD
  const hashId = generateId().slice(0,5);
  const BUCKET = `gs://${PROJECT_ID}.appspot.com`;
  const FOLDER = `backup/${TODAY}-${hashId}`;
  const FULL_PATH = `${BUCKET}/${FOLDER}`;

  await client.exportDocuments({
    name: DB_NAME,outputUriPrefix: FULL_PATH,collectionIds: [] // CAN LIST SPECIFIC COLLECTIONS
  });

  console.log(`Backup successfully exported`);
  return res.status(200).send("Ok");

};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?