Firebase可调用函数的中间件实现与通用逻辑提取方案咨询
Firebase Callable Functions 类中间件能力实现方案
核心实现逻辑
Firebase Callable Functions 没有内置类似 Express 的中间件机制,我们可以通过高阶函数封装实现同等的前置校验、逻辑复用能力:将通用的前置逻辑抽为独立的中间件函数,在业务代码执行前按顺序执行,遇到不符合要求的请求直接抛出错误拦截,无需在每个业务函数中重复编写校验逻辑。
具体实现步骤
1. 封装中间件执行高阶函数
首先定义通用的包装函数,负责接收中间件数组和实际的业务处理函数,按顺序执行中间件链条:
import * as functions from "firebase-functions"; // 中间件类型定义:参数为可调用函数的入参、上下文、共享透传状态,返回错误则直接拦截请求 type Middleware = ( data: unknown, context: functions.https.CallableContext, state: Record<string, unknown> ) => functions.https.HttpsError | Promise<functions.https.HttpsError | void>; /** * 可调用函数中间件包装器 * @param middlewares 要执行的中间件数组,按顺序执行 * @param handler 实际业务处理函数 */ const withMiddleware = ( middlewares: Middleware[], handler: ( data: unknown, context: functions.https.CallableContext, state: Record<string, unknown> ) => Promise<unknown> | unknown ) => { return functions.https.onCall(async (data, context) => { const state = {}; // 依次执行所有中间件 for (const middleware of middlewares) { const error = await middleware(data, context, state); if (error) throw error; } // 中间件全部通过,执行业务逻辑 return handler(data, context, state); }); };
2. 编写通用中间件
把身份校验、权限判断、参数校验、限流等通用逻辑抽为独立的中间件:
// 示例:登录状态校验中间件 const authMiddleware: Middleware = (data, context) => { if (!context.auth) { return new functions.https.HttpsError("unauthenticated", "请求需要登录身份"); } }; // 示例:管理员权限校验中间件 const adminPermissionMiddleware: Middleware = (data, context) => { if (context.auth?.token?.role !== "admin") { return new functions.https.HttpsError("permission-denied", "无管理员操作权限"); } }; // 示例:参数校验中间件 const createUserParamMiddleware: Middleware = (data) => { if (!data.phone || !data.username) { return new functions.https.HttpsError("invalid-argument", "缺少必填参数"); } };
3. 业务函数使用封装
直接用withMiddleware包装业务函数,按需传入需要的中间件即可:
// 创建用户接口:需要登录+管理员权限+参数校验 export const createUser = withMiddleware( [authMiddleware, adminPermissionMiddleware, createUserParamMiddleware], async (data, context, state) => { // 此处直接编写业务逻辑,无需再重复做前置校验 return { success: true, userId: "xxx" }; } ); // 普通用户查询个人信息接口:只需要登录校验 export const getUserInfo = withMiddleware( [authMiddleware], async (data, context, state) => { return { user: context.auth }; } );
多可调用函数时的通用功能优化方案
当可调用函数数量较多时,可以通过以下方式进一步提升复用性、降低维护成本:
- 中间件按用途分类归档:将所有通用中间件抽入独立目录(如
/middlewares),按用途分为auth.ts、permission.ts、validator.ts、rateLimit.ts等,不同业务场景按需导入组合。 - 封装常用中间件组合:如果大量函数需要相同的中间件链条,直接将组合封装为独立的包装器,避免每个函数重复编写中间件数组:
// 封装通用的管理员接口包装器,所有管理后台接口直接复用 const withAdminAuth = (handler: Parameters<typeof withMiddleware>[1]) => { return withMiddleware([authMiddleware, adminPermissionMiddleware, rateLimitMiddleware], handler); }; // 管理端接口直接使用包装器即可,无需重复声明中间件 export const deleteUser = withAdminAuth(async (data) => { // 业务逻辑 }); export const updateSystemConfig = withAdminAuth(async (data) => { // 业务逻辑 });
- 支持状态透传:中间件处理后的数据(如查询到的用户完整信息、权限配置等)可以存入
state参数透传给后续中间件和业务函数,避免重复查询数据库。
内容的提问来源于stack exchange,提问作者Johnny Oshika
相关产品推荐
相关产品推荐

