You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将JOI validator作为中间件添加到Firebase function中?

解决方案

Firebase HTTPS Callable 函数的处理函数接收的是(data, context)两个参数,而非Express的(req, res),原Express的Joi中间件无法直接复用,我们可以通过高阶校验包装函数实现类似的中间件效果,原有业务逻辑完全不需要修改。


步骤1:定义通用Joi校验包装函数

const Joi = require('joi');
// 若使用v2版本firebase-functions,导入方式如下:
const { HttpsError } = require('firebase-functions/v2/https');
// 若使用v1版本firebase-functions,替换为下面的导入:
// const functions = require('firebase-functions');
// const HttpsError = functions.https.HttpsError;

// 通用Joi校验高阶函数,入参为校验规则schema、原业务处理函数
const validateJoi = (schema, handler) => {
  return async (data, context) => {
    // abortEarly设为false可返回所有校验不通过的字段提示,默认仅返回第一个
    const { error } = schema.validate(data, { abortEarly: false });
    if (error) {
      // 抛出Firebase标准HTTPS错误,客户端可正常识别错误信息
      throw new HttpsError(
        'invalid-argument',
        '参数校验不通过',
        error.details.map(item => item.message)
      );
    }
    // 校验通过,执行业务逻辑
    return handler(data, context);
  };
};

步骤2:定义业务对应的Joi校验Schema

以创建用户账号场景为例:

const createUserSchema = Joi.object({
  email: Joi.string().email().required().messages({
    'string.email': '邮箱格式不正确',
    'any.required': '邮箱为必填项'
  }),
  password: Joi.string().min(6).required().messages({
    'string.min': '密码长度不能少于6位',
    'any.required': '密码为必填项'
  }),
  nickname: Joi.string().max(20).optional()
});

步骤3:包装原业务函数注册到Firebase云函数

// 原createAccount函数完全保持不变,不需要修改任何逻辑
const createAccount = async (data, context) => {
  // 你的原有业务逻辑
  return {
    success: true,
    userId: 'xxxx'
  };
};

// 注册云函数时用validateJoi包装原函数即可
exports.createUserAccount = region("europe-east1")
  .https
  .onCall(validateJoi(createUserSchema, createAccount));

额外说明

  • 如果只有单个函数需要校验,不需要复用逻辑,也可以直接在createAccount函数开头调用Joi校验逻辑,不需要单独封装高阶函数
  • 校验失败抛出的HttpsError会被Firebase自动处理,返回对应错误码和信息给调用端,不需要自己构造返回值

内容的提问来源于stack exchange,提问作者markWanka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 13:06:02