【问题标题】:Callable Cloud Functions Returning Null in Flutter在 Flutter 中返回 Null 的可调用云函数
【发布时间】: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。我将更新问题以更好地解释这一点。

标签: firebase flutter google-cloud-functions flutter-web


【解决方案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>;

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 2014-05-12
    • 1970-01-01
    • 2020-02-04
    • 2021-01-11
    相关资源
    最近更新 更多