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

问题描述 投票:0回答:3

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

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

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}
    });

  });

然后我在 Flutter 中创建了一个

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);
}

最后,我用另一个错误处理程序从

TextButton
调用我的未来:

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/hosted/pub.dartlang.org/cloud_functions_platfrom_interface-5..0.15/lib/src/method_channel/method_channel_https_callable.dart
)。

它停在班级

MethodChannelHttpsCallable
的功能
call
,就在这里:

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.
    }

最后,一旦我单击

Step Over
(在 VSCode 中),以下内容就会打印到控制台:

出现此错误:

[firebase_functions/failed-precondition] 故意错误。

#0 StandardMethodCodec.decodeEnvelope 包:flutter/…/services/message_codecs.dart:597

#1 MethodChannel._invokeMethod 包:flutter/…/services/platform_channel.dart:158

#2 MethodChannelHttpsCallable.call 包:cloud_functions_platform_interface/…/method_channel/method_channel_https_callable.dart:23

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

得到这个文档 ID:null
firebase flutter google-cloud-functions
3个回答
0
投票

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

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

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

null
值。

在这种情况下你可以做的是

rethrow
在第一个错误处理程序中按照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
省略重新抛出/抛出语句:

Caught error: [firebase_functions/failed-precondition] Error on purpose Final result: //Incorrectly continues code, seems to not be handling errors
    

0
投票
我建议检查谷歌云控制台中的日志。 有时,内部错误是由于函数体不正确或参数传递方式不正确造成的。

请参阅此 ->

Firebase 管理 SDK FCM 错误 需要主题、令牌或条件之一


-1
投票
我不太确定为什么,但这解决了问题:

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

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(); }
    
© www.soinside.com 2019 - 2024. All rights reserved.