尝试通过 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
问题描述
我正在尝试运行此代码来实现 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屋!