You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Post请求报错但仍创建费用对象,金额类型转换存疑

问题分析与解决方案

一、"Failed to create expense"错误但数据已添加的原因

这个问题核心是后端已成功创建费用数据,但返回的HTTP状态码不是代码中判断的201,导致前端抛出异常,但数据实际已写入数据库。

排查与解决步骤:

  1. 确认后端真实返回内容:在createExpense方法中添加日志,打印响应状态码和响应体,明确后端的实际返回:
    Future<Expenses> createExpense(String category,int amount,String date,String paymentType) async {
      final response = await http.post(...);
      // 添加日志排查
      print('状态码:${response.statusCode}');
      print('响应体:${response.body}');
      
      if (response.statusCode == 201) {
        return Expenses.fromJson(jsonDecode(response.body));
      } else {
        throw Exception('Failed to create expense.');
      }
    }
    
  2. 调整状态码判断逻辑:如果后端用200表示创建成功(部分后端的标准),将判断条件改为response.statusCode == 200,或根据后端文档要求修改。
  3. 检查后端逻辑:确认后端是否存在"先写入数据库,再返回错误响应"的逻辑漏洞,比如数据插入成功后,后续校验或处理失败导致返回非成功状态码。

二、金额字段处理的优化

当前流程(输入字符串→int.parse→toString)冗余且无校验,易引发异常:

优化方案:

  1. 限制输入为整数:给金额输入框添加键盘类型和过滤器,避免非数字输入:
    TextField(
      controller: _amountInput,
      decoration: const InputDecoration(hintText: 'Enter amount'),
      keyboardType: TextInputType.number,
      inputFormatters: [FilteringTextInputFormatter.digitsOnly], // 仅允许输入数字
    )
    
  2. 减少不必要的类型转换:如果后端接受字符串格式的整数,直接传递输入内容即可:
    • 修改createExpense参数与请求体:
      Future<Expenses> createExpense(String category, String amount, String date, String paymentType) async {
        final response = await http.post(
          Uri.parse('****************'),
          headers: <String, String>{
            'Content-Type': 'application/json; charset=UTF-8',
          },
          body: jsonEncode(<String, String>{
              'category': category,
              'amount': amount, // 直接传输入的字符串
              'date': date,
              'paymentType': paymentType
          }),
        );
        // 状态码判断逻辑不变
      }
      
    • 修改按钮调用逻辑:
      ElevatedButton(
        onPressed: () {
          final amount = _amountInput.text.trim();
          // 添加空值校验
          if (amount.isEmpty) {
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('请输入金额')),
            );
            return;
          }
          setState(() {
            _futureExpense = createExpense(_controller.text, amount, _dateInput.text, _typeInput.text);
          });
        },
        child: const Text('Create Data'),
      )
      
  3. 添加格式校验:若需确保金额是整数,用int.tryParse替代int.parse避免异常:
    onPressed: () {
      final amountStr = _amountInput.text.trim();
      final amount = int.tryParse(amountStr);
      if (amount == null) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('请输入有效的整数金额')),
        );
        return;
      }
      // 后续调用逻辑
    }
    

三、额外体验优化

在buildFutureBuilder中,请求完成后添加按钮让用户回到输入界面:

FutureBuilder<Expenses> buildFutureBuilder() {
  return FutureBuilder<Expenses>(
    future: _futureExpense,
    builder: (context, snapshot) {
      if (snapshot.hasData) {
        return Column(
          children: [
            Text(snapshot.data!.category!),
            ElevatedButton(
              onPressed: () => setState(() => _futureExpense = null),
              child: const Text('添加新费用'),
            ),
          ],
        );
      } else if (snapshot.hasError) {
        return Column(
          children: [
            Text('${snapshot.error}'),
            ElevatedButton(
              onPressed: () => setState(() => _futureExpense = null),
              child: const Text('重新尝试'),
            ),
          ],
        );
      }
      return const CircularProgressIndicator();
    },
  );
}

内容的提问来源于stack exchange,提问作者User G Amsterdam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 05:55:19