Flutter应用+Deno+MongoDB后端注册功能出现类型转换异常问题
解决Flutter注册时
type 'Null' is not a subtype of type 'String'错误 这个错误的核心原因是你的Flutter前端代码期望后端返回特定字段,但Deno后端的注册接口返回的字段不匹配,导致前端解析时拿到null值,赋值给String类型变量时触发类型错误。
具体问题分析
看一下你的Flutter auth.dart里的_authenticate方法:
_token = responseData['idToken']; _userId = responseData['localId']; _expiryDate = DateTime.now().add( Duration( seconds: int.parse( responseData['expiresIn'], ), ), );
这段代码默认后端会返回idToken、localId、expiresIn这三个字段,但你的Deno后端register接口返回的是:
ctx.response.body = { id: user.id, name: user.name, email: user.email };
完全没有前端需要的那三个字段,所以responseData['idToken']等调用返回的是null,而_token、_userId是String类型,赋值null就会抛出Null is not a subtype of String错误。
另外还有一个隐藏问题:你的前端错误处理依赖后端返回responseData['error']['message'],但后端当前的错误响应是{ message: "Email is already exist" },这也会导致前端解析错误时出现问题。
解决方案(推荐方案:调整后端匹配前端期望)
修改Deno的auth_controller.ts,调整返回格式,同时引入JWT生成认证token(生产环境建议用JWT库,比如djwt):
// 先安装djwt库:deno add djwt import { createToken } from "https://deno.land/x/djwt@v3.0.1/mod.ts"; async register(ctx: RouterContext) { const { email, password } = await ctx.request.body().value; let user = await User.findOne({ email }); if (user) { ctx.response.status = 422; // 调整错误格式匹配前端的HttpException解析逻辑 ctx.response.body = { error: { message: "Email is already exist" } }; return; } const hashedPassword = hashSync(password); user = new User({ email, password: hashedPassword }); await user.save(); // 生成JWT token,设置过期时间为1小时 const secretKey = new TextEncoder().encode('your-strong-secret-key-here'); // 生产环境要使用环境变量存储密钥 const payload = { localId: user.id, email: user.email, exp: Math.floor(Date.now() / 1000) + 3600 // 过期时间:当前时间+3600秒(1小时) }; const idToken = await createToken({ alg: "HS256", typ: "JWT" }, payload, secretKey); // 返回前端需要的字段 ctx.response.status = 201; ctx.response.body = { idToken: idToken, localId: user.id, expiresIn: "3600", // 过期时间(秒) id: user.id, name: user.name, email: user.email }; }
备选方案:调整前端适配后端当前格式
如果暂时不想修改后端,可以调整Flutter的_authenticate方法,适配现有后端返回:
Future<void> _authenticate( String email, String password, String urlSegment, ) async { final url = Uri.parse('http://10.0.2.2:8000/api/$urlSegment'); try { final response = await http.post( url, body: json.encode( { 'email': email, 'password': password, }, ), ); final responseData = json.decode(response.body); // 适配后端的错误响应格式 if (response.statusCode == 422) { throw HttpException(responseData['message']); } // 使用后端返回的id作为用户标识,自己设置过期时间 _token = responseData['id']; // 生产环境建议还是用JWT,这里只是临时适配 _userId = responseData['id']; _expiryDate = DateTime.now().add( Duration(hours: 1), // 自定义过期时间 ); _autoLogout(); notifyListeners(); final prefs = await SharedPreferences.getInstance(); final userData = json.encode( { 'token': _token, 'userId': _userId, 'expiryDate': _expiryDate!.toIso8601String(), }, ); prefs.setString('userData', userData); } catch (error) { throw error; } }
验证步骤
- 重启Deno后端服务
- 重新运行Flutter应用
- 测试注册功能,应该不会再出现空值类型错误,同时错误提示也能正常显示
内容的提问来源于stack exchange,提问作者GoodMan
相关产品推荐
相关产品推荐

