NodeJS 如何在Firebase可调用云函数上抛出错误?

qacovj5a  于 2023-08-04  发布在  Node.js
关注(0)|答案(2)|浏览(108)

我正在尝试使用可调用的云函数在Firebase上创建一个新用户。每当出现错误时(例如:电子邮件无效)无论我做什么,函数总是向我的Firebase应用程序返回相同的神秘错误:

{"error":{"status":"INTERNAL","message":"INTERNAL"}}

字符串
在Firebase控制台中,我也得到了这个:

Unhandled error Error: Unknown error status: auth/invalid-email


这没有多大意义,因为我实际上是在处理错误。这是云函数的代码:

exports.createUser = (data, context) => {
    return admin.auth().createUser({
        email: data.email,
        password: data.password
    }).catch((error) => {
        throw new functions.https.HttpsError(error.errorInfo.code, error.errorInfo.message);
    });
}


如图所示,我尝试使用文档中建议的throw functions.https.HttpsError
我也试过return functions.https.HttpsError,甚至抛出了我自己的错误,结果都是一样的。
我在await中使用try/catch,而不是使用then()catch()。同样的结果。函数控制台仍然通知我错误没有处理,这是荒谬的。
那么,在使用可调用云函数时,如何向用户抛出适当的错误呢?

ru9i0ody

ru9i0ody1#

看起来您试图沿着来自Admin SDK的错误代码,但这不是一个有效的策略。仔细阅读文档-它会将您发送到API documentation for HttpsError以查找可发送的有效错误代码列表。code属性链接到FunctionsErrorCode,它显示有效代码的列表:
“好的”|“取消”|“未知”|“无效论元”|“逾期”|“未找到”|“已经存在”|“拒绝许可”|“资源枯竭型”|“失败前提”|“中止”|“超出范围”|“未执行”|“内部”|“不可用”|“数据丢失”|“未经认证”
Admin SDK给你的是“auth/invalid-email”,这里是无效的。你得把它转换成有效的密码。也许“无效论证”是合适的。这将被进一步转换为一个数字HTTP响应代码,您将在客户端上收到该代码。

g2ieeal7

g2ieeal72#

有两种方法可以将错误从Firebase Cloud Function抛回客户端。无论如何,您必须在错误前面加上一个经过批准的Firebase字符串标识符,例如invalid-argumentalready-exists。您可以在API参考中找到完整的列表。然而,我并不觉得它们特别有用,因为我不得不将这些标识符都没有很好描述的错误返回给客户机。因此,我更喜欢使用“unknown”标识符,它在已批准的列表中,并构造自己的错误供客户机解析。
将错误抛回客户端的第一种方法是简单地将云函数本身生成的任何错误都抛回。

exports.test = functions.https.onCall(async (_data, _context) => {
    try {
        // something that throws...
    } catch (error) {
        throw new functions.https.HttpsError("unknown", error);
    }
});

字符串
如果你总是使用unknown标识符,客户端将很难解析这个错误,但如果你只是想抛出一个错误来终止这个函数调用,而你不想让客户端解析它,这是最基本的实现。
如果你想稍微改进一下这个实现,你可以在错误中附加一个自定义的标识符,客户端可以解析它,这通常可以在错误的本地化描述中找到(在客户端)。您也不需要在抛出的错误中包含错误对象本身,您只需追加字符串标识符即可。

exports.test = functions.https.onCall(async (_data, _context) => {
    try {
        // something that throws...
    } catch (error) {
        throw new functions.https.HttpsError("unknown", "custom-identifier", error);
    }
});


第二种通用方法是将自己的错误抛回客户端。下面是一个可能的用例示例,其中在函数中遇到错误,而不是抛出错误来终止函数调用,而是尝试先进行一些清理。如果清理成功,那么您可以抛出一个软错误。如果清理失败,这可能是有问题的,那么您可以抛出一个硬错误(可能会将一个自定义警告记录到控制台,以便稍后有人可以处理它)。

exports.test = functions.https.onCall(async (_data, _context) => {
    try {
        // something that throws...
    } catch (initialError) {

        // An error has occurred in the above try closure.

        try {
            // Attempt to clean up this error.

            // If you've successfully cleaned up the initial error, 
            // throw a local error to the catch block below.
            // Notice this is a plain error, not an HttpsError.
            throw new Error("local-error");
        } catch (cleanupError) {
            if (error.message == "local-error") {

                // This is the error thrown by us locally. We've averted a disaster.
                // Now throw the client an error and, optionally, pass it the initial error.
                throw new functions.https.HttpsError("unknown", "soft-client-error", initialError);
            } else {

                // This is the error thrown by the attempt to clean up the initial 
                // error. This may be a big problem! Alert the client of a hard
                // error and, optionally, pass it all the errors along the way.
                throw new functions.https.HttpsError("unknown", "hard-client-error", {initialError: initialError, cleanupError: cleanupError});
            }
        }
    }
});


注意不要用参数重载抛出的错误,因为限制是三个。第一个参数是代码,它是兼容Firebase的字符串标识符,第二个参数是消息,第三个参数是详细信息。在许多客户端上,第二个参数被视为错误的本地化描述,第三个参数被视为其详细信息。

相关问题