当前位置: 首页 > 知识库问答 >
问题:

从Flatter调用Firebase可调用函数时无法处理错误

谈旺
2023-03-14

我正在从Flatter调用Firebase可调用函数,尽管我已经尝试了几乎所有的方法,但仍然无法处理可调用函数抛出的错误。

我的可调用函数如下所示:

js prettyprint-override">import * as functions from "firebase-functions";

const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();

export const myFunction = functions.https.onCall((data, context) => {

    //Get data passed to the function
    const someData = data.someData;
    
    //Run transaction
    return db.runTransaction(async (transaction: any) => {
        //Get data
        const docRef = db.collection("myCollection").doc("myDocId");
        const docResults = await transaction.get(docRef);
        const docData = docResults.data();

        //Run validations:
        if(1 != 0){
            throw new functions.https.HttpsError('failed-precondition', "Error on purpose");
        }
        
        //Create a new doc
        const newDocRef = db.collection('myCollection').doc();
        transaction.set(newDocRef, {someData: "myData",});

        return {newDocId: newDocRef.id}
    });

  });

然后,我在flatter中创建了一个Future来调用我的可调用函数:

import 'package:cloud_functions/cloud_functions.dart';

Future<String> callMyFunction({String someData,}) async {
  HttpsCallable callable = FirebaseFunctions.instance.httpsCallable(
      'myFunction',  options: HttpsCallableOptions(timeout: Duration(seconds: 5)));

  try {
    return callable.call({
      'someData': someData,
    }).then((results) {
      return results.data['newDocId'].toString();
    }).catchError(handleError); //First error handler
  } catch (error) {
    //Second error handler
    print("Missed the first error handler.");
    handleError(error);
    return null;
  }
}

void handleError(error) {
  print("Got this error:");
  print(error);
}

最后,我用另一个错误处理程序从一个文本按钮调用我的未来:

import 'package:flutter/material.dart';
import 'package:myApp/callableFuture.dart';

class myWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return TextButton(
      child: Text("Press me"),
      onPressed: () {
        callMyFunction(
          someData: "Hi",
        ).catchError((error) {
          //This is my third error handler
          print("Missed first two error handlers. Got this error:");
          print(error);
        }).then((newDocId) =>
            print("Got this doc id: $newDocId"));
      },
    );
  }
}

当我调用我的函数并得到一个错误时,我的代码立即跳转到-并停止在-Flutter的method_channel_https_callable.dart(位于.../flutter/. pub-cache/托管/pub.dartlang.org/cloud_functions_platfrom_interface-5..0.15/lib/src/method_channel/method_channel_https_callable.dart)。

它停在函数call处的类Method odChannelHttpsCallable,就在这里:

try {
      //...some code...

      if (result is Map) {
        return Map<String, dynamic>.from(result);
      } else {
        return result;
      }
    } catch (e, s) {
      throw convertPlatformException(e, s); //My code stops right here.
    }

最后,在VSCode中单击单步执行后,控制台会显示以下内容:

出现以下错误:

[firebase\u函数/失败的前提条件]故意出错。

#0 StandardMethodCodec。decodeEnvelope包:flatter/../services/message\u编解码器。dart:597

_invokeMethod包:flutter/.../service/platform_channel.dart:158

#2方法通道HttpScalable。调用包:cloud\u functions\u platform\u interface/../method\u channel/method\u channel\u https\u callable。省道:23

#3 HttpsCallable.call包:cloud_functions/src/https_callable.dart:35

共有2个答案

艾泉
2023-03-14

我真的不知道为什么,但这解决了问题:

我改变了调用可调用函数的未来:

import 'package:cloud_functions/cloud_functions.dart';

Future<String> callMyFunction({String someData,}) async {
  HttpsCallable callable = FirebaseFunctions.instance.httpsCallable(
      'myFunction',  options: HttpsCallableOptions(timeout: Duration(seconds: 5)));

  try {
    return callable.call({
      'someData': someData,
    }).then((results) {
      return results.data['newDocId'].toString();
    }).catchError(handleError); //First error handler
  } catch (error) {
    //Second error handler
    print("Missed the first error handler.");
    handleError(error);
    return null;
  }
}

void handleError(error) {
  print("Got this error:");
  print(error);
}

为此:

import 'package:cloud_functions/cloud_functions.dart';

Future<String> callMyFunction({String someData,}) async {
  HttpsCallable callable = FirebaseFunctions.instance.httpsCallable(
      'myFunction',  options: HttpsCallableOptions(timeout: Duration(seconds: 5)));

  HttpsCallableResult results;

  try {
    results = await callable.call({
      'someData': someData,
    });
  } catch (error) {
    print("Got this error:");
    print(error.code);
    print(error.message);
    return null;
  }

  return results.data['newDocId'].toString();
}
盖斌
2023-03-14

通过查看您的输出日志和代码,很明显您的第一个错误处理程序正在根据以下行为您解析或处理错误:

I/flutter (21112): Got this error: I/flutter (21112): [firebase_functions/failed-precondition] Error on purpose.

由于来自Firebase函数的错误由第一个错误处理程序处理(或“解决”),因此其他两个错误处理程序没有理由运行,因为它们没有收到任何错误。这使得从您的按钮执行的Future要被解析,尽管具有null值。

在这种情况下,您可以做的是按照Dart中建议的那样,在您的第一个错误处理程序中重新抛出错误,因此它可以在第二个处理程序中处理,并再次将其重新抛出到第三个处理程序。我相信在这种情况下,第二个处理程序是多余的,您可以将错误从第一个处理程序重新抛出到第三个处理程序。catchError()子句已经在Dart中用作try/catch块。

Firebase函数

exports.myFuncEmu = functions.https.onCall((data,context) => {
  const testData = data.text;

  if(testData == "throwEx"){
    throw new functions.https.HttpsError('failed-precondition', "Error on purpose");
  }

  console.log(testData);
  return `Finished: ${testData}`
});

扑腾未来

Future<String?> runFunction(String text) async {
  await Firebase.initializeApp();
  FirebaseFunctions.instance.useFunctionsEmulator('localhost', 5001);
  HttpsCallable callableFunc =
      FirebaseFunctions.instance.httpsCallable("myFuncEmu");

  try {
    return await callableFunc.call(
      {"text": text},
    ).then((res) {
      return res.data.toString();
    }).catchError(handleError); //Handler from callable function
  } catch (err) {
    print("Missed the first error handler"); //Try/catch block handler
    rethrow; //Throws here so it can be caught by Future handler in button widget
    return null;
  }
}

String handleError(err) {
  print("Caught error: ");
  print(err);
  throw Exception(err); //Throws here so it can be caught by try/catch handler
  return "";
}

颤振按钮

child: ElevatedButton( //Swapped order of then and catcherror clauses
                onPressed: () {
                  runFunction("throwEx")
                      .then((val) => print("Final result: ${val}"))
                      .catchError((err) {
                    print(
                        "Missed first two error handlers"); //Handler from Future function
                    print(err);
                  });
                },
                child: const Text(
                  "RUN",
                  style: TextStyle(color: Colors.white),
                ),
              ),

通过添加所需的throw/rethrow语句,我们可以通过错误处理程序正确重定向此错误,以便在发现错误后阻止代码执行:

Caught error:
[firebase_functions/failed-precondition] Error on purpose
Missed the first error handler
Missed first two error handlers
Exception: [firebase_functions/failed-precondition] Error on purpose

省略rethrow/throw语句:

Caught error:
[firebase_functions/failed-precondition] Error on purpose
Final result: //Incorrectly continues code, seems to not be handling errors
 类似资料:
  • 这是我的客户电话: My REACT_APP_FIREBASE_CALLABLE在本地设置为http://localhost:5001,部署时不使用。 我的firebase模拟器正在运行,它们在本地模拟我的函数: 我似乎无法让部署的版本调用函数。在日志中,函数根本没有被调用。 有人帮忙吗?

  • 问题内容: 现在,我有几次遇到使用Firebase的同步和异步功能的问题。我的问题通常是我需要在我编写的函数中进行异步Firebase调用。作为一个简单的示例,假设我需要计算并显示对象的速度,而我的Firebase存储距离和时间: 当然,上述代码将无法使用,因为它是异步调用,因此在到达时尚未设置。如果我们将内部放置在回调函数中,则什么也不会返回。 一种解决方案是使我的函数也异步。 另一种解决方案是

  • 问题内容: 提交表单(ajax调用)后,我试图选择并集中于所选的组件ID。 此解决方案有效,但是存在问题,即称为AFTER ,因此在选择组件后呈现了表单,并清除了焦点。 呈现表单后如何调用函数? 更新:( 例如,我尝试过) 添加到=>导致刷新页面 添加到=>与属性相同的行为 接下来是attr。=>还是一样 update2 (应如何工作): 提交按钮被称为ajax 根据需要清洁表格 重点关注适当的领

  • 我正在处理平台频道(PlatformChannels),试图从Kotlin(Kotlin)到Flatter(颤振)进行通信。尝试实际执行颤振平台频道文档中解释的操作,但方向相反: 通道文件颤振平台 其思想是从MainActivity上的ConfigureFlatterEngine函数调用颤振函数。kt级。 为此,我做了,在颤振方面,梅因。dart(颤振的默认示例): 从Kotlin方面来说,我只是

  • 这对我来说很神秘。我知道函数被正确调用是因为 > 我可以在云功能日志“Received query Roud and Cleary:”中看到我的打印内容。 当删除行并返回一些虚拟数据时,函数将正确执行。

  • 我有一个简单的firebase functions脚本设置(运行firebase admin 8.0版和firebase functions 2.3.1版): 该函数的目标只是返回用户的IP地址。它在函数控制台中记录良好,没有错误。 这是客户端代码: 但是,控制台表示“result”不是有效的JSON对象。 我尝试过使用互联网上其他人推荐的https.on呼叫,但是,控制台说该功能不存在。 任何帮