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

Flutter+GetX注册报错:type 'Null' is not a subtype of type 'String'

问题根因

你遇到的Unhandled Exception: type 'Null' is not a subtype of type 'String'是典型的空安全强转错误,代码里多处滥用强制非空操作符!,把实际为null的值强行赋值给非空String类型变量,具体触发点有4个:

  • 注册页回调中直接使用status.success!、status.enMessage!,只要接口返回字段缺失就会直接崩溃
  • 注册成功分支中未做判空直接取response.body["token"],传给要求非空String参数的saveUserToken方法,一旦接口200返回但没带token字段就会报错
  • 请求失败分支中直接使用可空类型的response.statusText赋值给非空参数,网络超时、域名解析失败时statusText本身就是null,直接触发类型错误
  • ApiClient的请求头缺失Content-Type: application/json配置,GetX默认post请求编码格式不是JSON,后端解析请求失败会返回非预期格式,导致所有响应字段解析为null
修复方案

按顺序改完下面的代码就能解决问题:

1. 修复注册页逻辑

替换原有注册方法代码,去掉强制非空,加入参校验:

void _freelancerRegistration(AuthController authController) {
  // 先校验表单入参,避免null值传给接口
  if (name.isEmpty || email.isEmpty || password.isEmpty || phone.isEmpty) {
    Utils.flushBarErrorMessage("请填写完整注册信息", context);
    return;
  }
  SignUpBody signUpBody = SignUpBody(
      name: name, email: email, password: password, phone: phone);
  authController.registration(signUpBody).then((status) {
    // 用??操作符给空值兜底,禁止直接用!强转
    if (status.success ?? false) {
      print('注册成功');
      // 这里写注册成功后的跳转、存储逻辑
    } else {
      Utils.flushBarErrorMessage(status.enMessage ?? "注册失败,请稍后重试", context);
    }
  });
}

2. 修复AuthController空安全问题

替换原有registration、login方法代码,所有可空字段都加判空兜底:

Future<ResponseModel> registration(SignUpBody signUpBody) async {
  _isLoading = true;
  update();
  Response response = await authRepo.registration(signUpBody);
  late ResponseModel responseModel;
  if (response.statusCode == 200) {
    // 先判空再取token
    String? token = response.body?["token"];
    if (token != null && token.isNotEmpty) {
      authRepo.saveUserToken(token);
      responseModel = ResponseModel(success: true, enMessage: "注册成功");
    } else {
      responseModel = ResponseModel(success: false, enMessage: "返回数据异常,未获取到登录凭证");
    }
  } else {
    // 给statusText加空兜底
    responseModel = ResponseModel(
        success: false, enMessage: response.statusText ?? "网络请求失败,请检查网络连接");
  }
  _isLoading = false;
  update();
  return responseModel;
}

Future<ResponseModel> login(String email, String password) async {
  print('Getting Token');
  print(authRepo.getUserToken().toString());
  _isLoading = true;
  update();
  Response response = await authRepo.login(email, password);
  late ResponseModel responseModel;
  if (response.statusCode == 200) {
    print('Backend Token');
    String? token = response.body?["token"];
    if (token != null && token.isNotEmpty) {
      authRepo.saveUserToken(token);
      print(token.toString());
      responseModel = ResponseModel(success: true, enMessage: "登录成功");
    } else {
      responseModel = ResponseModel(success: false, enMessage: "返回数据异常,未获取到登录凭证");
    }
  } else {
    // 去掉原有的!强转,加空兜底
    responseModel = ResponseModel(
        success: false, enMessage: response.statusText ?? "账号或密码错误");
  }
  _isLoading = false;
  update();
  return responseModel;
}

3. 修复ApiClient请求头配置

给请求头加JSON格式声明,避免后端解析请求失败:

ApiClient({required this.appBaseUrl, required this.sharedPreferences}) {
  baseUrl = appBaseUrl;
  timeout = const Duration(seconds: 30);
  token = sharedPreferences.getString(AppConstants.TOKEN) ?? "";
  _mainHeaders = {
    'Content-Type': 'application/json; charset=UTF-8',
    'Accept': 'application/json',
    'Authorization': 'Bearer $token',
  };
}
void updateHeader(String token) {
  _mainHeaders = {
    'Content-Type': 'application/json; charset=UTF-8',
    'Accept': 'application/json',
    'Authorization': 'Bearer $token',
  };
}

4. 表单配置检查

确认你的name、email、password、phone四个表单变量默认值是空字符串'',而不是null,从源头上避免空值传入请求体。

调试技巧:后续遇到同类空类型报错,直接在Android Studio/VS Code里开启未捕获异常断点,报错时会直接定位到出错的代码行,不用逐行排查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:06:51