Flutter获取MongoDB聊天室数据时FormatException错误解决
Flutter获取MongoDB聊天室数据触发FormatException问题解决
问题场景
在Flutter项目中调用接口获取MongoDB中的聊天室数据时,触发未处理的FormatException,错误提示:
FormatException: Unexpected character (at character 2)
{_id: 6414a040c01cb2fbea9ede6c, chatTopic: Current Affairs, roomType: publi...
^
相关代码与响应
ChatRoomServices代码
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:onpods/constants/http_error_handelling.dart'; import 'package:onpods/constants/utils.dart'; import 'package:onpods/models/chat_room_model.dart'; import 'package:onpods/models/user_model.dart'; import 'package:http/http.dart' as http; import 'package:onpods/providers/user_provider.dart'; import 'package:onpods/view/chat_room.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:provider/provider.dart'; import '../../constants/global_constants.dart'; class ChatRoomServices { void getChatRoomIndex({ required BuildContext context, }) async { http.Response res = await http.get( Uri.parse("$uri/get-all-room-index"), headers: <String, String>{ 'Content-Type': 'application/json; charset=UTF-8', }, ); print("skjnv"); print(jsonDecode(res.body)[0]); List<ChatRoomModel> allChatRooms = []; for (var e in jsonDecode(res.body)) { ChatRoomModel temp = ChatRoomModel.fromJson(e.toString()); allChatRooms.add(temp); print(temp.chatTopic); print(temp.chatTopic); } print("skjnv"); ChatRoom chatRoom; // ignore: use_build_context_synchronously httpErrorHandle( response: res, context: context, onSuccess: () async {}, ); } }
ChatRoomModel代码
import 'dart:convert'; // ignore_for_file: public_member_api_docs, sort_constructors_first class ChatRoomModel { String chatTopic; String roomType; Map<String, dynamic> ownerId; List<Map<String, dynamic>> speakers; List<Map<String, dynamic>> participants; String createdAt; String updatedAt; ChatRoomModel({ required this.chatTopic, required this.roomType, required this.ownerId, required this.speakers, required this.participants, required this.createdAt, required this.updatedAt, }); Map<String, dynamic> toMap() { return <String, dynamic>{ 'chatTopic': chatTopic, 'roomType': roomType, 'ownerId': ownerId, 'speakers': speakers, 'participants': participants, 'createdAt': createdAt, 'updatedAt': updatedAt, }; } factory ChatRoomModel.fromMap(Map<String, dynamic> map) { return ChatRoomModel( chatTopic: map['chatTopic'] as String, roomType: map['roomType'] as String, ownerId: Map<String, dynamic>.from((map['ownerId'] as Map<String, dynamic>)), speakers: List<Map<String, dynamic>>.from( (map['speakers'] as List<int>).map<Map<String, dynamic>>( (x) => x as Map<String, dynamic>, ), ), participants: List<Map<String, dynamic>>.from( (map['participants'] as List<int>).map<Map<String, dynamic>>( (x) => x as Map<String, dynamic>, ), ), createdAt: map['createdAt'] as String, updatedAt: map['updatedAt'] as String, ); } String toJson() => json.encode(toMap()); factory ChatRoomModel.fromJson(String source) { print("Sajs"); print(source); return ChatRoomModel.fromMap(json.decode(source) as Map<String, dynamic>); } }
Postman接口响应(/get-all-room-index)
[ { "_id": "6414a040c01cb2fbea9ede6c", "chatTopic": "Current Affairs", "roomType": "public", "ownerId": { "isPublic": true, "_id": "6405fe3df459de43b5dadb78", "user_name": "Simran Bhalode", "user_email": "simran@gmail.com", "user_password": "$2b$07$VPHjLNYKicBcEgfyRNT9i.8zok9kU7XqNlNgnpAsZ5V9FN/oyKUka", "user_role": "admin", "registered_date": "2023-03-06T14:52:45.847Z", "__v": 0 }, "speakers": [ { "isPublic": true, "_id": "6405fe3df459de43b5dadb78", "user_name": "Simran Bhalode", "user_email": "simran@gmail.com", "user_password": "$2b$07$VPHjLNYKicBcEgfyRNT9i.8zok9kU7XqNlNgnpAsZ5V9FN/oyKUka", "user_role": "admin", "registered_date": "2023-03-06T14:52:45.847Z", "__v": 0 } ], "participants": [], "createdAt": "2023-03-17T17:15:44.873Z", "updatedAt": "2023-03-17T17:15:44.873Z", "__v": 0 }, { "_id": "6415e11ddd95481799b016f7", "chatTopic": "Current Affairs", "roomType": "public", "ownerId": { "isPublic": true, "_id": "6405fe3df459de43b5dadb78", "user_name": "Simran Bhalode", "user_email": "simran@gmail.com", "user_password": "$2b$07$VPHjLNYKicBcEgfyRNT9i.8zok9kU7XqNlNgnpAsZ5V9FN/oyKUka", "user_role": "admin", "registered_date": "2023-03-06T14:52:45.847Z", "__v": 0 }, "speakers": [ { "isPublic": true, "_id": "6405fe3df459de43b5dadb78", "user_name": "Simran Bhalode", "user_email": "simran@gmail.com", "user_password": "$2b$07$VPHjLNYKicBcEgfyRNT9i.8zok9kU7XqNlNgnpAsZ5V9FN/oyKUka", "user_role": "admin", "registered_date": "2023-03-06T14:52:45.847Z", "__v": 0 } ], "participants": [], "createdAt": "2023-03-18T16:04:45.928Z", "updatedAt": "2023-03-18T16:04:45.928Z", "__v": 0 } ]
错误栈信息
[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: FormatException: Unexpected character (at character 2) {_id: 6414a040c01cb2fbea9ede6c, chatTopic: Current Affairs, roomType: publi... ^ #0 _ChunkedJsonParser.fail (dart:convert-patch/convert_patch.dart:1383:5) #1 _ChunkedJsonParser.parse (dart:convert-patch/convert_patch.dart:913:48) #2 _parseJson (dart:convert-patch/convert_patch.dart:35:10) #3 JsonDecoder.convert (dart:convert/json.dart:610:36) #4 JsonCodec.decode (dart:convert/json.dart:216:41) #5 new ChatRoomModel.fromJson chat_room_model.dart:59 #6 ChatRoomServices.getChatRoomIndex chat_room_services.dart:33 <asynchronous suspension>
解决方案
核心问题分析
- 错误调用fromJson:
jsonDecode(res.body)已经将接口响应解析为List<Map<String, dynamic>>,但循环中把每个Map对象转成字符串(e.toString())传给fromJson,而fromJson要求输入合法JSON字符串,但e.toString()生成的是Dart对象的字符串表示(无引号的键名,不符合JSON规范),导致解析失败。 - Model类型转换错误:
ChatRoomModel.fromMap中把speakers和participants声明为List<int>,但接口返回的是用户对象数组,类型不匹配。
修改步骤
1. 修正ChatRoomServices中的对象转换逻辑
直接使用fromMap解析已解码的Map对象,无需转字符串:
// 替换原循环代码 List<ChatRoomModel> allChatRooms = []; final decodedData = jsonDecode(res.body) as List<dynamic>; for (var e in decodedData) { ChatRoomModel temp = ChatRoomModel.fromMap(e as Map<String, dynamic>); allChatRooms.add(temp); print(temp.chatTopic); }
2. 修正ChatRoomModel中的类型转换
将speakers和participants的List<int>改为List<dynamic>:
// 修改fromMap方法中的对应部分 speakers: List<Map<String, dynamic>>.from( (map['speakers'] as List<dynamic>).map<Map<String, dynamic>>( (x) => x as Map<String, dynamic>, ), ), participants: List<Map<String, dynamic>>.from( (map['participants'] as List<dynamic>).map<Map<String, dynamic>>( (x) => x as Map<String, dynamic>, ), ),
验证
修改后重新调用接口,即可正常解析聊天室数据,不再触发FormatException。
内容的提问来源于stack exchange,提问作者Sahil
相关产品推荐
相关产品推荐

