尝试通过 Next.js API 路由上的 admin.firestore.v1.FirestoreAdminClient 导出备份.错误:无法加载默认凭据 [英] Trying to export backup via admin.firestore.v1.FirestoreAdminClient on a Next.js API route. Error: Could not load the default credentials

查看:74
本文介绍了尝试通过 Next.js API 路由上的 admin.firestore.v1.FirestoreAdminClient 导出备份.错误:无法加载默认凭据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

const backupHandler: NextApiHandler = async (req,res) =>{尝试 {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-DDconst hashId = generateId().slice(0,5);const BUCKET = `gs://${PROJECT_ID}.appspot.com`;const FOLDER = `firestore-backup/${TODAY}-${hashId}`;const FULL_PATH = `${BUCKET}/${FOLDER}`;等待 client.exportDocuments({名称:DB_NAME,outputUriPrefix: FULL_PATH,collectionIds: []//可以列出特定的集合});console.log(`备份成功导出`);返回 res.status(200).send("Ok");}抓住(错误){控制台日志(错误);返回 res.status(500).send(服务器错误");}};

这是initializeFirebaseAdmin()函数

type FirebaseAdmin = typeof import(firebase-admin/lib/firebase-namespace")const getServiceAccount = () : admin.ServiceAccount =>{if (process.env.VERCEL_ENV === "生产";||process.env.VERCEL_GIT_COMMIT_REF === 暂存") {返回 SERVICE_ACCOUNT.PROD;}否则返回SERVICE_ACCOUNT.TEST;};export const initializeFirebaseAdmin = (): FirebaseAdmin =>{const account = getServiceAccount();//这将获得服务帐户(通过下载的 .json 文件)const PROJECT_ID = getProjectId();如果(!admin.apps.length){admin.initializeApp({凭证:admin.credential.cert(account),databaseURL: `https://${PROJECT_ID}.firebaseio.com`//我试过和没有这行:相同的结果});}返回管理员;};

这是我得到的错误:

<块引用>

错误:无法加载默认凭据.浏览到

起初我只是使用 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";//或者从一些单一的 initializeFirebaseAdmin 函数中导入它import { NextApiHandler } from "next";从some-path/serviceAccount.json"导入SERVICE_ACCOUNT;interface CredentialBody {//从 google-auth-library 复制此信息 >认证 >证书client_email?: 字符串;private_key?:字符串;}const backupHandler: NextApiHandler = async (req,res) =>{const 客户端 = 新 admin.firestore.v1.FirestoreAdminClient({凭证:SERVICE_ACCOUNT 作为 CredentialBody//<<<<<<这是重要的部分});const PROJECT_ID = getProjectId();const DB_NAME = client.databasePath(PROJECT_ID, "(default)");const TODAY = getToday();//YYYY-MM-DDconst hashId = generateId().slice(0,5);const BUCKET = `gs://${PROJECT_ID}.appspot.com`;const FOLDER = `backup/${TODAY}-${hashId}`;const FULL_PATH = `${BUCKET}/${FOLDER}`;等待 client.exportDocuments({名称:DB_NAME,outputUriPrefix: FULL_PATH,collectionIds: []//可以列出特定的集合});console.log(`备份成功导出`);返回 res.status(200).send("Ok");};

I'm trying to run this code to implement a Firestore backup.

But for the first time, I'm deploying it into a Next.js project.

I'll hit it on my /api/backup endpoint.

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");
  }
  
};

This is the initializeFirebaseAdmin() function

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;
};

This is the error I'm getting:

Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information. at GoogleAuth.getApplicationDefaultAsync (/var/task/node_modules/google-auth-library/build/src/auth/googleauth.js:173:19)

At first I was just using the credential property. Then I added the databaseURL to see if it would solve the issue, but still, same result.

I think I'm initializing the firebase-admin properly. Not sure what is going wrong here.


UPDATE: Just found out that this very same code works fine on my local environment (in development), but does not work on my Next.js Node.js environment when I deploy it. What could be going wrong?

解决方案

After days in hell, just found out what I was doing wrong.

I'm using new admin.firestore.v1.FirestoreAdminClient(); because firebase-admin itself won't expose any methods for us to access the exportDocuments() functionality.

But the fact is, when you instantiate the FirestoreAdminClient like that, it will not have access to the credentials that you've used on admin.initializeApp({credentials}).

So you need to pass the credentials to the client, by doing:

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");

};

这篇关于尝试通过 Next.js API 路由上的 admin.firestore.v1.FirestoreAdminClient 导出备份.错误:无法加载默认凭据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆