Flutter应用分配用户角色时遇NoSuchMethodError及JSON解析异常
Flutter角色分配功能请求错误排查与修复
问题描述
开发Flutter应用的用户角色分配功能时,向数据库表发送数据出现两类错误:
- FormatException:JSON解析异常
- NoSuchMethodError:调用null对象的idUser属性
Postman测试SQL查询一切正常,但Flutter端发送请求时触发上述错误。
错误日志
I/flutter (26238): Error: FormatException: Unexpected character (at character 1) I/flutter (26238): SyntaxError: Unexpected token n in JSON at position 0 I/flutter (26238): ^ I/flutter (26238): Usuario elegido: 3 I/flutter (26238): Rol elegido: 3 E/flutter (26238): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: NoSuchMethodError: The getter 'idUser' was called on null. E/flutter (26238): Receiver: null E/flutter (26238): Tried calling: idUser E/flutter (26238): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5) E/flutter (26238): #1 AdministratorRolesAssignController.assignRol (package:palser_delivery_app/src/pages/administrator/roles/assign/administrator_roles_assign_controller.dart:53:39)
Rol模型代码
import 'dart:convert'; import 'package:palser_delivery_app/src/models/user.dart'; Rol rolFromJson(String str) => Rol.fromJson(json.decode(str)); String rolToJson(Rol data) => json.encode(data.toJson()); class Rol { String id; String name; String image; String route; String idUser; String idRol; List<Rol> roles; List<Rol> toList = []; User user; Rol({ this.id, this.name, this.image, this.route, this.idUser, this.idRol, this.roles, this.user, }); factory Rol.fromJson(Map<String, dynamic> json) => Rol( id: json["id"] is int ? json["id"].toString() : json["id"], name: json["name"], image: json["image"], route: json["route"], idUser: json["id_user"], idRol: json["id_rol"], roles: json["roles"] == null ? [] : List<Rol>.from(json['roles'].map((model) => Rol.fromJson(model))) ?? [], user: json['user'] is String ? userFromJson(json['user']) : json['user'] is User ? json['user'] : User.fromJson(json['user'] ?? {}), ); Rol.fromJsonList(List<dynamic> jsonList) { if (jsonList == null) return; jsonList.forEach((item) { Rol rol = Rol.fromJson(item); toList.add(rol); }); } Map<String, dynamic> toJson() => { "id": id, "name": name, "image": image, "route": route, "id_user": idUser, "id_rol": idRol, "roles": roles, "user": user, }; }
Roles Provider代码
import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:palser_delivery_app/src/api/environment/environment.dart'; import 'package:palser_delivery_app/src/models/response_api.dart'; import 'package:palser_delivery_app/src/models/rol.dart'; import 'package:palser_delivery_app/src/models/roles_assignment.dart'; import 'package:palser_delivery_app/src/models/user.dart'; import 'package:http/http.dart' as http; import 'package:palser_delivery_app/src/utils/shared_pref.dart'; class RolesProvider { String _url = Environment.API_DELIVERY; String _api = '/api/roles'; String _apiusers = 'api/users'; BuildContext context; User sessionUser; Future init(BuildContext context, User sessionUser) { this.context = context; this.sessionUser = sessionUser; } Future<List<Rol>> getAll() async { try { Uri url = Uri.http(_url, '$_api/getAll'); Map<String, String> headers = { 'Content-type': 'application/json', 'Authorization': sessionUser.sessionToken }; final res = await http.get(url, headers: headers); if (res.statusCode == 401) { // 未授权 Fluttertoast.showToast(msg: '会话已过期'); new SharedPref().logout(context, sessionUser.id); } final data = json.decode(res.body); Rol rol = Rol.fromJsonList(data); return rol.toList; } catch(e) { print('ERROR: $e'); return null; } } Future<List<User>> getAllUsers() async { try { Uri url = Uri.http(_url, '$_apiusers/getAll'); Map<String, String> headers = { 'Content-type': 'application/json', 'Authorization': sessionUser.sessionToken }; final res = await http.get(url, headers: headers); if (res.statusCode == 401) { // 未授权 Fluttertoast.showToast(msg: '会话已过期'); new SharedPref().logout(context, sessionUser.id); } final data = json.decode(res.body); User user = User.fromJsonList(data); return user.toList; } catch(e) { print('ERROR: $e'); return null; } } Future<List<Rol>> getRoles() async { try { Uri url = Uri.http(_url, '$_api/getRoles'); Map<String, String> headers = { 'Content-type': 'application/json', 'Authorization': sessionUser.sessionToken }; final res = await http.get(url, headers: headers); if (res.statusCode == 401) { // 未授权 Fluttertoast.showToast(msg: '会话已过期'); new SharedPref().logout(context, sessionUser.id); } final data = json.decode(res.body); Rol rol = Rol.fromJsonList(data); return rol.toList; } catch(e) { print('ERROR: $e'); return null; } } Future<ResponseApi> assignRol(Rol rol) async { try{ Uri url = Uri.http(_url, '$_api/assign'); String bodyParams = json.encode(rol); Map<String, String> headers = { 'Content-type': 'application/json', 'Authorization': sessionUser.sessionToken }; final res = await http.post(url, headers: headers, body: bodyParams); if (res.statusCode == 401) { Fluttertoast.showToast(msg: '会话已过期'); new SharedPref().logout(context, sessionUser.id); } final data = json.decode(res.body); ResponseApi responseApi = ResponseApi.fromJson(data); return responseApi; } catch(e) { print('Error: $e'); return null; } } }
Controller代码
import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:palser_delivery_app/src/models/response_api.dart'; import 'package:palser_delivery_app/src/models/rol.dart'; import 'package:palser_delivery_app/src/models/user.dart'; import 'package:palser_delivery_app/src/provider/roles_provider.dart'; import 'package:palser_delivery_app/src/provider/users_provider.dart'; import 'package:palser_delivery_app/src/utils/my_snackbar.dart'; import 'package:palser_delivery_app/src/utils/shared_pref.dart'; class AdministratorRolesAssignController { BuildContext context; Function refresh; SharedPref _sharedPref = new SharedPref(); User user; List<User> users = []; UsersProvider _usersProvider = new UsersProvider(); Rol rol; List<Rol> roles = []; RolesProvider _rolesProvider = new RolesProvider(); String idUser; String idRol; Future init(BuildContext context, Function refresh, Rol rol) async { this.context = context; this.refresh = refresh; this.rol = rol; user = User.fromJson(await _sharedPref.read('user')); _usersProvider.init(context, sessionUser: user); _rolesProvider.init(context, user); getUsers(); getRoles(); refresh(); } void assignRol() async { rol?.idUser = idUser; rol?.idRol = idRol; ResponseApi responseApi = await _rolesProvider.assignRol(rol); // MySnackBar.show(context, responseApi.message); print('Usuario elegido: ${idUser}'); print('Rol elegido: ${idRol}'); print('Usuario enviado: ${rol.idUser}'); print('Rol enviado: ${rol.idRol}'); // } } void getUsers() async { users = await _usersProvider.getAllUsers(); refresh(); } void getRoles() async { roles = await _rolesProvider.getRoles(); refresh(); } }
错误修复方案
1. 解决NoSuchMethodError(调用null对象的idUser属性)
- 问题根源:Controller中的
rol对象为null,设置属性时用了空安全操作避免赋值报错,但后续打印rol.idUser未做空判断,触发空指针异常。同时需确认页面初始化时是否正确传递了Rol实例。 - 修复步骤:
- 在
assignRol方法开头添加空判断,提前终止错误流程:void assignRol() async { if (rol == null) { print('Rol对象为空,请检查初始化参数'); return; } rol.idUser = idUser; rol.idRol = idRol; // 后续代码... } - 修改打印语句,添加空安全操作符:
print('Usuario enviado: ${rol?.idUser}'); print('Rol enviado: ${rol?.idRol}'); - 检查页面跳转逻辑,确保传递给
AdministratorRolesAssignController.init的rol参数是有效实例。
- 在
2. 解决FormatException(JSON解析异常)
- 问题根源:后端接口返回的不是合法JSON格式,而是错误文本(如日志中的语法错误提示),导致Flutter解析失败。Postman测试正常但Flutter报错,可能是请求参数格式不一致触发后端错误。
- 修复步骤:
- 在
RolesProvider的assignRol方法中添加响应打印,排查后端返回内容:Future<ResponseApi> assignRol(Rol rol) async { try{ // ... 原有代码 ... final res = await http.post(url, headers: headers, body: bodyParams); print('后端响应内容:${res.body}'); // 添加打印 if (res.statusCode == 401) { // ... 原有代码 ... } // ... 原有代码 ... } catch(e) { print('Error: $e'); return null; } } - 根据打印结果调整后端接口,确保无论成功还是失败都返回标准JSON响应。
- 对比Flutter与Postman的请求参数,检查Rol对象序列化后的JSON是否符合后端要求(比如
user或roles字段是否无法被正确序列化)。
- 在
内容的提问来源于stack exchange,提问作者Marcelo_uy
相关产品推荐
相关产品推荐

