部署Firebase Functions遇错误:需提供配置选项的疑问
Firebase Functions部署报错"Need to provide options"的解决办法
问题场景
我通过index.ts部署Firebase Functions,使用命令:
firebase deploy --only functions
部署时触发以下错误:
Error: Failed to load function definition from source: Failed to generate manifest from function source: FirebaseError: Firebase: Need to provide options, when not being deployed to hosting via source. (app/no-options).
对应的index.ts代码如下:
import { getDatabase, ref, get, child } from "firebase/database"; import * as functions from "firebase-functions"; import * as cors from "cors"; import * as express from "express"; import * as bodyParser from "body-parser"; import { AnyExercise, Workout } from "./types"; const app = express(); // parse application/x-www-form-urlencoded app.use(bodyParser.urlencoded({ extended: false })); // Automatically allow cross-origin requests app.use(cors({ origin: true })); // parse application/json app.use(bodyParser.json()); const dbRef = ref(getDatabase()); app.get("/workouts/:userId", (req, res) => { get(child(dbRef, `workouts/${req.params.userId}`)) .then((snapshot) => { if (snapshot.exists()) { console.log("workouts", snapshot.val()); return snapshot.val(); } else { console.log("No data available"); return null; } }) .then((workouts: Record<Workout["id"], Workout>) => { if (!workouts) { res.send({ workoutObj: {}, exerciseListByWorkout: {} }); } get(child(dbRef, "exercises")).then((snapshot) => { if (snapshot.exists()) { const exercises: Record<AnyExercise["id"], AnyExercise> = snapshot.val(); console.log("exercises", exercises); const mappedExercises: Record<Workout["id"], AnyExercise[]> = {}; Object.values(workouts).forEach((workout) => { const exList: any[] = []; workout.exerciseList?.forEach((exId) => { const ex = exercises && exercises[exId]; if (ex) { exList.push(ex); } }); mappedExercises[workout.id] = exList; }); res.send({ workoutObj: [], exerciseListByWorkout: mappedExercises }); } else { console.log("No data available"); res.send({ workoutObj: workouts, exerciseListByWorkout: {} }); } }); }) .catch((error) => { console.error(error); res.send(error); }); }); // Expose Express API as a single Cloud Function: export const api = functions.https.onRequest(app);
错误解析与解决方案
这个错误的本质是你误用了Firebase客户端SDK来初始化数据库。客户端SDK是给前端应用用的,需要显式传入Firebase项目配置(比如apiKey、projectId等)才能工作;而在Cloud Functions环境中,必须使用Firebase Admin SDK来访问数据库等服务——Admin SDK会自动通过环境变量获取当前项目的配置,不需要手动传入选项。
解决步骤如下:
- 安装Firebase Admin SDK
在项目根目录执行命令:
npm install firebase-admin
- 替换数据库初始化代码
把原来的客户端SDK导入和初始化代码,替换为Admin SDK的写法:
// 替换原来的import { getDatabase... } import * as admin from "firebase-admin"; // 初始化Admin SDK(Cloud Functions环境下无需传参) admin.initializeApp(); // 获取数据库引用 const db = admin.database(); const dbRef = db.ref();
- 适配数据库操作代码
Admin SDK的数据库操作API和客户端SDK几乎一致,大部分代码可以直接保留,只需要把get(child(dbRef, ...))调整为dbRef.child(...).get()(两种写法其实都能运行,后者更符合Admin SDK的习惯)。
另外,你的代码里有个小bug:返回响应时workoutObj被错误地设为空数组,应该传入实际的workouts数据,我在下面的完整代码里已经修正了这个问题。
修改后的完整代码
import * as admin from "firebase-admin"; import * as functions from "firebase-functions"; import * as cors from "cors"; import * as express from "express"; import * as bodyParser from "body-parser"; import { AnyExercise, Workout } from "./types"; // 初始化Firebase Admin SDK admin.initializeApp(); const app = express(); // 解析表单编码数据 app.use(bodyParser.urlencoded({ extended: false })); // 允许跨域请求 app.use(cors({ origin: true })); // 解析JSON数据 app.use(bodyParser.json()); const db = admin.database(); const dbRef = db.ref(); app.get("/workouts/:userId", (req, res) => { dbRef.child(`workouts/${req.params.userId}`).get() .then((snapshot) => { if (snapshot.exists()) { console.log("workouts", snapshot.val()); return snapshot.val(); } else { console.log("No data available"); return null; } }) .then((workouts: Record<Workout["id"], Workout>) => { if (!workouts) { return res.send({ workoutObj: {}, exerciseListByWorkout: {} }); } return dbRef.child("exercises").get().then((snapshot) => { if (snapshot.exists()) { const exercises: Record<AnyExercise["id"], AnyExercise> = snapshot.val(); console.log("exercises", exercises); const mappedExercises: Record<Workout["id"], AnyExercise[]> = {}; Object.values(workouts).forEach((workout) => { const exList: AnyExercise[] = []; workout.exerciseList?.forEach((exId) => { const ex = exercises[exId]; if (ex) { exList.push(ex); } }); mappedExercises[workout.id] = exList; }); return res.send({ workoutObj: workouts, exerciseListByWorkout: mappedExercises }); } else { console.log("No data available"); return res.send({ workoutObj: workouts, exerciseListByWorkout: {} }); } }); }) .catch((error) => { console.error(error); res.status(500).send({ error: error.message }); }); }); // 将Express应用暴露为Cloud Function export const api = functions.https.onRequest(app);
内容的提问来源于stack exchange,提问作者Kasey Kaufmann
相关产品推荐
相关产品推荐

