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

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实例。
  • 修复步骤:
    1. 在assignRol方法开头添加空判断,提前终止错误流程:
      void assignRol() async {
        if (rol == null) {
          print('Rol对象为空,请检查初始化参数');
          return;
        }
        rol.idUser = idUser;
        rol.idRol = idRol;
        // 后续代码...
      }
      
    2. 修改打印语句,添加空安全操作符:
      print('Usuario enviado: ${rol?.idUser}');
      print('Rol enviado: ${rol?.idRol}');
      
    3. 检查页面跳转逻辑,确保传递给AdministratorRolesAssignController.init的rol参数是有效实例。

2. 解决FormatException(JSON解析异常)

  • 问题根源:后端接口返回的不是合法JSON格式,而是错误文本(如日志中的语法错误提示),导致Flutter解析失败。Postman测试正常但Flutter报错,可能是请求参数格式不一致触发后端错误。
  • 修复步骤:
    1. 在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;
        }
      }
      
    2. 根据打印结果调整后端接口,确保无论成功还是失败都返回标准JSON响应。
    3. 对比Flutter与Postman的请求参数,检查Rol对象序列化后的JSON是否符合后端要求(比如user或roles字段是否无法被正确序列化)。

内容的提问来源于stack exchange,提问作者Marcelo_uy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 17:49:58