Flutter请求服务器时遇FormatException错误与302状态码问题求助
Flutter请求服务器返回302错误及JSON解析异常排查
问题详情
向服务器发送数据时返回状态码302,同时触发未处理异常:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: FormatException: Unexpected character (at character 1) E/flutter ( 5424): E/flutter ( 5424): ^ E/flutter ( 5424): E/flutter ( 5424): #0 _ChunkedJsonParser.fail (dart:convert-patch/convert_patch.dart:1383:5) E/flutter ( 5424): #1 _ChunkedJsonParser.parseNumber (dart:convert-patch/convert_patch.dart:1250:9) E/flutter ( 5424): #2 _ChunkedJsonParser.parse (dart:convert-patch/convert_patch.dart:915:22) E/flutter (5424): #3 _parseJson (dart:convert-patch/convert_patch.dart:35:10) E/flutter (5424): #4 JsonDecoder.convert (dart:convert/json.dart:612:36) E/flutter (5424): #5 JsonCodec.decode (dart:convert/json.dart:216:41) E/flutter ( 5424): #6 LoginCubit.auth (package:muraba/features/presentation/login/cubit/login_cubit.dart:29:16) E/flutter ( 5424): E/flutter ( 5424): #7 LoginBody.build. (package:muraba/features/presentation/login/login.dart:144:21) E/flutter ( 5424): E/flutter ( 5424):E/flutter (5424):
相关代码
请求逻辑代码
Future<void> auth(int number, String device_key)async { emit(LoginLoading()); final response = await http.post(Uri.parse(ConfigUrl.sendMessage), body: jsonEncode(<String, dynamic>{ "phone": number "device_key": device_key })); if(response.statusCode == 200) { final responseJson = json.decode(response.body) as Map<String, dynamic>; print(responseJson); emit(LoginLoaded(loginModel: LoginModel.fromJson(responseJson))); } else { print(response.statusCode); log(json.decode(response.body)); emit(LoginError()); } }
按钮触发代码
Container( margin: EdgeInsets.fromLTRB(10, 0, 10, 20), child: InkWell( onTap: () async { final number = int.parse(_numberEditingController.text); const device_key = 'asdarwefvxcgczxcvvd'; await context.read<LoginCubit>().auth(number, device_key); // context.go('/home'); }, child: Container( width: double.infinity color: Colors.green, padding: EdgeInsets.symmetric(vertical: 14), child: Text('Continue', style: TextStyle(fontSize: 19), textAlign: TextAlign.center,), ), ), )
服务器响应截图

问题分析
- 请求参数语法错误:
jsonEncode中的Map键值对之间缺少逗号("phone": number后未加逗号),导致生成的JSON格式非法,服务器无法正确解析请求。 - 302重定向未处理:状态码302表示请求需要重定向到其他地址,但
http.post默认不自动跟随重定向,且重定向后的响应体通常不是JSON格式,直接调用json.decode会抛出FormatException。 - 异常处理缺失:else分支中直接解析响应体,未考虑非JSON格式的情况,导致未处理异常触发。
- 请求头缺失:未设置
Content-Type: application/json,服务器可能无法识别请求体为JSON格式,进而返回异常响应。
修复方案
1. 修复请求逻辑代码
补充缺失的逗号、添加请求头并完善异常处理:
Future<void> auth(int number, String device_key) async { emit(LoginLoading()); try { final response = await http.post( Uri.parse(ConfigUrl.sendMessage), headers: {'Content-Type': 'application/json'}, // 声明请求体格式 body: jsonEncode(<String, dynamic>{ "phone": number, // 添加缺失的逗号 "device_key": device_key }), ); if (response.statusCode == 200) { final responseJson = json.decode(response.body) as Map<String, dynamic>; print(responseJson); emit(LoginLoaded(loginModel: LoginModel.fromJson(responseJson))); } else if (response.statusCode == 302) { // 处理重定向逻辑,获取Location头地址 final redirectUrl = response.headers['location']; if (redirectUrl != null) { print("重定向地址: $redirectUrl"); // 可选:跟随重定向重新发起请求 // final redirectResponse = await http.get(Uri.parse(redirectUrl)); } emit(LoginError(message: "请求被重定向")); } else { print(response.statusCode); print("响应体内容: ${response.body}"); emit(LoginError(message: "请求失败,状态码${response.statusCode}")); } } catch (e) { print("请求或解析异常: $e"); emit(LoginError(message: "请求出错")); } }
2. 修复按钮代码语法错误
在width: double.infinity后添加缺失的逗号:
Container( margin: EdgeInsets.fromLTRB(10, 0, 10, 20), child: InkWell( onTap: () async { final number = int.parse(_numberEditingController.text); const device_key = 'asdarwefvxcgczxcvvd'; await context.read<LoginCubit>().auth(number, device_key); // context.go('/home'); }, child: Container( width: double.infinity, // 添加缺失的逗号 color: Colors.green, padding: EdgeInsets.symmetric(vertical: 14), child: Text('Continue', style: TextStyle(fontSize: 19), textAlign: TextAlign.center,), ), ), )
内容的提问来源于stack exchange,提问作者Daniil
相关产品推荐
相关产品推荐

