在 Flutter 中返回 Null 的可调用云函数

Posted

技术标签:

【中文标题】在 Flutter 中返回 Null 的可调用云函数【英文标题】:Callable Cloud Functions Returning Null in Flutter 【发布时间】:2021-01-24 21:21:23 【问题描述】:

我的目标:

我希望在我的 Flutter App 中调用 Cloud Function 来检索 JSON obj 来自 Python-FastAPI 服务器,并在警报对话框中显示内容。

错误:

我的颤振应用程序中的可调用函数服务收到 null。我的警报对话框显示由我的代码触发的“空值错误”。

云端操作:

我的云功能分为两部分:

Callable Http Function中从客户端(Flutter APP)接收数据 调用 Python API => 返回云函数,返回客户端

云功能:

exports.getRandomPassword = functions.https.onCall(async (data, context) => 
  const useSymbols = data.useSymbols;
  const pwLength= data.pwLength;

  const debug =
    received_data_type: typeof data,
    received_data:data,
    pwLen_type: typeof pwLength,
    pwLength,
    useSymbols_type:typeof useSymbols,
    useSymbols,
  

  console.log(debug);
  await callAPI(pwLength,useSymbols).then((res:any) =>
    console.log(`Resulting Payload: $res`);
    return res);

);

Python-FastAPI 调用:

async function callAPI(pwLength: any, useSymbols: any) 
  // BUILD URL STRING WITH PARAMS
  const ROOT_URL = `http://[IP_Address]/password?pwd_length=$pwLength&use_symbols=$useSymbols`;
  let res;
  // let password: any; // password to be received

  await http.get(ROOT_URL)
    .then((response: any) => 
      console.log("TO APP "+JSON.stringify(response));
      console.log(response.getBody());
      res = response.getBody() as Map<any, any>;

    )
    .catch((err: any) => 
      console.log(err);
      res= err;
    );

  return res;

生成的有效负载可以正常工作,如我的日志中所示:

客户端操作:

在 Flutter 中点击按钮:

                        onPressed: () async 
                          // call cloud function & use set state to store pw
                          await getPassword().then((String result) 
                            setState(() 
                              password = result;
                            );
                          );
                          showDialog(
                              context: context,
                              builder: (context) => DisplayPassword());
                        ,

我的 Flutter getPassword() 函数:

Future<String> getPassword() async 
  var pw;
  final HttpsCallable callable = new CloudFunctions()
      .getHttpsCallable(functionName: 'getRandomPassword')
        ..timeout = const Duration(seconds: 30);

  try 
    await callable.call(
      <String, dynamic>
        'pwLength': 10,
        'useSymbols': true,
      ,
    ).then((value) 
      print(value.data);
      print(value.data.runtimeType);
      pw = value.data;
      return pw;
    );
   on CloudFunctionsException catch (e) 
    print('caught firebase functions exception');
    print('Code: $e.code\nmessage: $e.message\ndetails: $e.details');

    return '$e.details';
   catch (e) 
    print('caught generic exception');
    print(e);
    return 'caught generic exception\n$e';
  

我的显示密码功能:

class DisplayPassword extends StatelessWidget 
  final String pw = (_MyPasswordGenPageState().password == null)
      ? 'null value error'
      : _MyPasswordGenPageState().password;

  @override
  Widget build(BuildContext context) 
    return AlertDialog(
      title: Text(pw),
    );
  

注意* 我想将密码检索保留为云功能,因此它可以在网络应用程序和移动设备上使用。但是,如果出现更好的解决方案,我愿意重构整个操作。

【问题讨论】:

也许我因为帖子的长度而错过了它,但问题是什么?什么不工作? 正如标题所示,云函数返回 null。我将更新问题以更好地解释这一点。 【参考方案1】:

解决方案:

为无状态小部件使用构造函数 避免.then() Cloud Functions 在async 函数中调用时应返回Promise.resolve()

点击按钮:


    dynamic result =
        await callable.call(<String, dynamic>
      'pwLength': 10,
      'useSymbols': true,
      //await the result before continuing
    );

    setState(() 
      // convert hashmap to list and get first val
      password = result.data.values.toList()[0];
      isLoading = false; // remove loading indicator
    );


  showDialog(
      context: context,
      builder: (context) =>
          DisplayPassword(password));


为了便于阅读,我在上面的代码中删除了异常处理

显示警报对话框:


    class DisplayPassword extends StatelessWidget 
      var password; // check if null
      DisplayPassword(this.password); // constructor
    
      @override
      Widget build(BuildContext context) 
        // make sure null value isn't being passed to alert dialog widget
        if (password == null) 
          password = 'null value error';
        
    
        return AlertDialog(
          title: Text(password),
        );
      
    

云功能:


exports.getRandomPassword = functions.https.onCall(async (data, context) => 
  const useSymbols = data.useSymbols;
  const pwLength= data.pwLength;
  let password;
  password = await callAPI(pwLength,useSymbols);

  const debug =
    received_data_type: typeof data,
    received_data:data,
    pwLen_type: typeof pwLength,
    pwLength,
    useSymbols_type:typeof useSymbols,
    useSymbols,
    ResultingPayloadType: typeof password,
    ResultingPayload: password,

  

  console.log(debug);

  return Promise.resolve(password)

);


async function callAPI(pwLength: any, useSymbols: any) 
  // BUILD URL STRING WITH PARAMS
  const ROOT_URL = `http://[My_Api_IP_Address]/password?pwd_length=$pwLength&use_symbols=$useSymbols`;

  const res = await http.get(ROOT_URL);
  console.log(res.getBody());
  return res.getBody() as Map<String , any>;



【讨论】:

以上是关于在 Flutter 中返回 Null 的可调用云函数的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Firebase 可调用云函数上引发错误?

可调用云函数比 HTTP 函数更好吗?

Firebase 可调用云函数 CORS 错误

firebase - 从可调用云函数访问数据库时应用检查失败

在flutter中获取JSON数据返回NULL

Flutter中的异步函数不返回null