使用 Flutter app + Deno + MongoDB 后端的奇怪错误

Posted

技术标签:

【中文标题】使用 Flutter app + Deno + MongoDB 后端的奇怪错误【英文标题】:Strange error using Flutter app + Deno + MongoDB backend 【发布时间】:2021-12-14 19:38:11 【问题描述】:

我想写一个简单的注册函数,这是我的代码:

auth_screen.dart:

  Future<void> _submit() async 
    if (!_formKey.currentState!.validate()) 
      // Invalid!
      return;
    
    _formKey.currentState!.save();
    setState(() 
      _isLoading = true;
    );
    try 
      if (_authMode == AuthMode.Login) 
        // Log user in
        await Provider.of<Auth>(context, listen: false).login(
          _authData['email'] as String,
          _authData['password'] as String,
        );
       else 
        // Sign user up
        await Provider.of<Auth>(context, listen: false).signup(
          _authData['email'] as String,
          _authData['password'] as String,
          
        );
      
     on HttpException catch (error) 
      var errorMessage = 'Authentication failed';
      print("this is the auth data");
      print(_authData);
      if (error.toString().contains('EMAIL_EXISTS')) 
        errorMessage = 'This email address is already in use.';
       else if (error.toString().contains('INVALID_EMAIL')) 
        errorMessage = 'This is not a valid email address';
       else if (error.toString().contains('WEAK_PASSWORD')) 
        errorMessage = 'This password is too weak.';
       else if (error.toString().contains('EMAIL_NOT_FOUND')) 
        errorMessage = 'Could not find a user with that email.';
       else if (error.toString().contains('INVALID_PASSWORD')) 
        errorMessage = 'Invalid password.';
      
      _showErrorDialog(errorMessage);
     catch (error) 
      var errorMessage = 'Could not authenticate you. Please try again later.' +
          error.toString();
      _showErrorDialog(errorMessage);
    

    setState(() 
      _isLoading = false;
    );
  

auth.dart:


  Future<void> signup(String email, String password) async 
    return _authenticate(email, password, 'register');
  

  Future<void> _authenticate(
      String email, String password, String urlSegment) async 

    final url = Uri.parse('http://10.0.2.2:8000/api/$urlSegment');
    // final url = Uri.http('http://localhost:8000/api/', 'urlSegment');
    try 
      final response = await http.post(
        url,
        body: json.encode(
          
            'email': email,
            'password': password,

            //'returnSecureToken': true,
          ,
        ),
      );
      final responseData = json.decode(response.body);
      if (responseData['error'] != null) 
        throw HttpException(responseData['error']['message']);
      
      _token = responseData['idToken'];
      _userId = responseData['localId'];
      _expiryDate = DateTime.now().add(
        Duration(
          seconds: int.parse(
            responseData['expiresIn'],
          ),
        ),
      );
      _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)部分:

auth_controller.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;
        ctx.response.body =  message: "Email is already exist" ;
        return;
    
    const hashedPassword = hashSync(password);
    user = new User( email, password: hashedPassword );
    await user.save();
    ctx.response.status = 201;
    ctx.response.body = 
        id: user.id,
        name: user.name,
        email: user.email
    ;

这是user.ts 类:


export default class User extends BaseModel 
    public id: string = "";
    public name: string = "";
    public email: string = "";
    public password: string = "";
    constructor( id = "", name = "", email = "", password = "" ) 
        super();
        this.id = id;
        this.name = name;
        this.email = email;
        this.password = password;
    
    static async findOne(params: object): Promise<User | null> 
        const user = await userCollection.findOne(params);
        if (!user) 
            return null;
        
        return new User(User.prepare(user));
    
    async save() 
        const _id = await userCollection.insertOne(this);
        this.id = _id;
        return this;
    


当我想在 android 模拟器上测试应用程序时收到此错误消息:

“Null”类型不是“String”类型的子类型

当我使用 Postman 尝试后端服务器并将 post 请求发送到 http://0.0.0.0:8000/api/register 地址时。我得到了正确的响应并且它有效,但我不知道为什么我使用 Flutter 应用程序会得到 Null 响应?

我尝试在应用程序的前端和后端打印变量,看起来它们都很好且正确,但我不明白为什么会收到此错误消息?!

【问题讨论】:

【参考方案1】:

可能你在这部分的地图中得到了一个空值,因为地图在找不到键时返回一个空值,请检查地图值是否不为空

    try 
      if (_authMode == AuthMode.Login) 
        // Log user in
        await Provider.of<Auth>(context, listen: false).login(
          _authData['email'] as String,  // can return a null value
          _authData['password'] as String,   // can return a null value
        );
       else 
        // Sign user up
        await Provider.of<Auth>(context, listen: false).signup(
          _authData['email'] as String,   // can return a null value
          _authData['password'] as String,   // can return a null value
          
        );
      
    

【讨论】:

不,它们不是,我可以打印它们的值。 但是您给了我线索,我发现问题出在这行代码中:const email, password = await ctx.request.body().value; 我无法打印电子邮件和密码值,它们似乎是 Null 变量!但我不知道为什么,因为他们与 Postman 合作得很好!【参考方案2】:

您似乎收到了 null 作为响应值,而不是 String

编辑:

 Future<void> signup(String email, String password) async 
    return _authenticate(email, password, 'register');
  

检查emailpassword 不是null。并获得正确的值。

【讨论】:

我知道,但我不知道为什么? 我发现问题出在这行代码中:const email, password = await ctx.request.body().value; 我无法打印电子邮件和密码值,它们似乎是 Null 变量!但我不知道为什么,因为他们与 Postman 合作得很好! @GoodMan 尝试编辑后的答案 它们工作正常,值不为空,我可以打印并查看它们。【参考方案3】:

其实问题出在这两行代码上:

_token = responseData['idToken']; _userId = responseData['localId'];

因为它没有传递这些数据作为后端的响应。

【讨论】:

以上是关于使用 Flutter app + Deno + MongoDB 后端的奇怪错误的主要内容,如果未能解决你的问题,请参考以下文章

2019 - 展望技术篇

腾讯第一季度员工平均月薪 7.6 万元;“淘宝特价版”App 正式更名为“淘特”;Deno 1.10 正式发布|极客头条...

极客日报第129期:腾讯一季度狂赚478亿!员工人均月薪7.6万;“淘宝特价版”App 正式更名为“淘特”;Deno 1.10 正式发布

deno学习三 官方提供的方便deno 安装方式

TypeScript--deno前置学习

Deno将停止使用TypeScript,并公布五项具体理由