Flutter表单POST请求后端接收成功却触发错误提示问题
表单提交后后端接收成功,但前端始终触发错误提示
填写表单发起POST请求,后端已成功接收数据并返回响应,但前端一直触发else分支的错误弹窗,无法定位原因。以下是完整的BorrowBook组件和PostFormInputField输入组件代码:
BorrowBook组件代码
class BorrowBook extends StatelessWidget { BorrowBook({Key? key}) : super(key: key); GlobalKey<FormState> _formKey = GlobalKey<FormState>(); TextEditingController _titleController = TextEditingController(); TextEditingController _authorController = TextEditingController(); TextEditingController _indexController = TextEditingController(); TextEditingController _dateController = TextEditingController(); TextEditingController _returnController = TextEditingController(); TextEditingController _nameController = TextEditingController(); PostController _postController = Get.put(PostController()); void _clearForm() { _titleController.clear(); _authorController.clear(); _indexController.clear(); _dateController.clear(); _returnController.clear(); _nameController.clear(); } // This is the postRequest method postRequest(userData, url) async { var response = await _client.post( Uri.parse(ProjectApis.requestUrl), body: json.encode(userData), headers: _projectApis.headers, ); return response; } // This is the sendUserRequest method sendUserRequest() async { var userData = { 'title': _titleController.text, 'author': _authorController.text, 'index': _indexController.text, 'borrow_date': _dateController.text, 'return_date': _returnController.text, 'borrowed_by': _nameController.text, }; var response = await _postController.postRequest(userData, ProjectApis.requestUrl); var body = json.decode(response.body); if (body['status'] == 'success') { _clearForm(); Get.snackbar( 'Success', 'Your request has been sent successfully', snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.green, margin: EdgeInsets.all(10), borderColor: Colors.green, borderWidth: 2, colorText: Colors.white, snackStyle: SnackStyle.FLOATING, duration: Duration(seconds: 2), ); } else { Get.snackbar( 'Error', 'Something went wrong', snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red, margin: EdgeInsets.all(10), borderColor: Colors.red, borderWidth: 2, colorText: Colors.white, snackStyle: SnackStyle.FLOATING, duration: Duration(seconds: 2), ); } } @override Widget build(BuildContext context) { double height = MediaQuery.of(context).size.height; double width = MediaQuery.of(context).size.width; return SafeArea( child: Scaffold( body: SingleChildScrollView( child: Padding( padding: ProjectStyle.padding(context), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ TopSection( width: width, backIcon: Icons.chevron_left_sharp, onPressed: () {}, text: "Borrow A Book", height: height, closeIcon: Icons.cancel_outlined, ), SizedBox(height: height * 0.02), Container( height: height * 0.2, width: width, decoration: BoxDecoration( color: ProjectColors.grey, borderRadius: BorderRadius.circular(10), image: DecorationImage( filterQuality: FilterQuality.high, image: NetworkImage( "https://images.unsplash.com/photo-1456513080510-7bf3a84b82f8?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTB8fGJvb2tzfGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=500&q=60", ), fit: BoxFit.cover, ), ), ), SizedBox(height: height * 0.02), Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Book Title", style: ProjectStyle.textStyle(context), ), SizedBox(height: height * 0.02), PostFormInputField( inputController: _titleController, hintText: "Enter Book Title", inputType: TextInputType.text, validate: (value) { if (value.isEmpty) { return "Please enter a title"; } return null; }, saved: (value) { _titleController.text = value; }, ), SizedBox(height: height * 0.02), Text( "Author Name", style: ProjectStyle.textStyle(context), ), SizedBox(height: height * 0.02), PostFormInputField( inputController: _authorController, hintText: "Enter Author Name", inputType: TextInputType.text, validate: (value) { if (value.isEmpty) { return 'Please enter Author Name'; } return null; }, saved: (value) { _authorController.text = value; }, ), SizedBox(height: height * 0.02), Text( "Student Index", style: ProjectStyle.textStyle(context), ), SizedBox(height: height * 0.02), PostFormInputField( inputController: _indexController, hintText: "Enter Your Index", inputType: TextInputType.text, validate: (value) { if (value.isEmpty) { return 'Please enter your index'; } return null; }, saved: (value) { _indexController.text = value; }, ), SizedBox(height: height * 0.02), Text( "Borrow Date", style: ProjectStyle.textStyle(context), ), SizedBox(height: height * 0.02), PostFormInputField( inputController: _dateController, hintText: "Enter Borrow Date", inputType: TextInputType.datetime, validate: (value) { if (value.isEmpty) { return 'Please enter Borrow Date'; } return null; }, saved: (value) { _dateController.text = value; }, ), SizedBox(height: height * 0.02), Text( "Return Date", style: ProjectStyle.textStyle(context), ), SizedBox(height: height * 0.02), PostFormInputField( inputController: _returnController, hintText: "Enter Return Date", inputType: TextInputType.datetime, validate: (value) { if (value.isEmpty) { return 'Please enter return date'; } return null; }, saved: (value) { _returnController.text = value; }, ), SizedBox(height: height * 0.02), Text( "Borrowed By", style: ProjectStyle.textStyle(context), ), SizedBox(height: height * 0.02), PostFormInputField( inputController: _nameController, hintText: "Enter Your Full Name", inputType: TextInputType.text, validate: (value) { if (value.isEmpty) { return 'Please enter your name'; } return null; }, saved: (value) { _nameController.text = value; }, ), SizedBox(height: height * 0.02), ElevatedButton( style: ElevatedButton.styleFrom( primary: ProjectColors.primary, minimumSize: Size(width * 0.95, height * 0.08), ), onPressed: () { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); sendUserRequest(); } }, child: Text("Submit Request"), ), SizedBox(height: height * 0.02), ], ), ), ], ), ), ), ), ); } }
PostFormInputField输入组件代码
class PostFormInputField extends StatelessWidget { const PostFormInputField({ Key? key, required this.inputController, required this.inputType, required this.hintText, required this.validate, required this.saved, }) : super(key: key); final TextEditingController inputController; final TextInputType inputType; final String hintText; final Function validate, saved; @override Widget build(BuildContext context) { return TextFormField( autovalidateMode: AutovalidateMode.onUserInteraction, controller: inputController, keyboardType: inputType, validator: (value) { return validate(value); }, onSaved: (value) { return saved(value); }, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide( color: ProjectColors.grey, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide( color: ProjectColors.grey, ), ), hintText: hintText, ), ); } }
排查与解决步骤
- 确认后端响应格式:前端判断逻辑依赖
body['status'] == 'success',但后端可能返回的status值不是小写success,或字段名不一致(如Status、code)。在sendUserRequest中添加print('后端响应体: ${response.body}'),查看控制台输出的实际响应内容,匹配判断条件。 - 检查响应状态码与解析:即使后端接收数据成功,也可能返回非200状态码,或
json.decode解析失败。先判断response.statusCode == 200,再进行后续解析操作,同时捕获解析异常。 - 核对PostController的postRequest实现:实际调用的是
_postController.postRequest,需确认该方法是否正确使用传入的url参数,以及请求头是否设置了Content-Type: application/json(确保后端能正确解析JSON)。 - 移除冗余的onSaved逻辑:TextFormField已绑定控制器,
onSaved中重复给控制器赋值属于冗余操作,可能引发意外问题。修改PostFormInputField,移除saved参数及对应的onSaved回调,表单提交时直接使用控制器的text值即可。
内容的提问来源于stack exchange,提问作者Kennedy Owusu
相关产品推荐
相关产品推荐

