鍍金池/ 問答/數據庫  網絡安全  HTML/ 數據庫操作套在回調函數中就出錯

數據庫操作套在回調函數中就出錯

實現一個注冊功能

user.post('/register', async(ctx) => {
    let {username, password, rePassword} = ctx.request.body;
    
    if (!username) {
        responseClient(ctx, 400, 2, '用戶名不可為空');
        return;
    }
    if (!password) {
        responseClient(ctx, 400, 2, '密碼不可為空');
        return;
    }
    if (password !== rePassword) {
        responseClient(ctx, 400, 2, '兩次密碼不一致');
        return;
    }   

    try{
       await User.findOne({username}, function(err, doc){
            if(err){
                 responseClient(ctx);
             }

             if(doc){
                 responseClient(ctx, 200, 1, '用戶名已存在');
                 return;  
             }else{
                 //保存到數據庫
                let user = new User({
                     username: username,
                     password: password,
                     type: 'user'
                 });

                 user.save(function(err, doc){
                     if(err){
                         console.log(err);
                     }
                     if(doc){
                         let data = {};
                         data.username = doc.username;
                         data.userType = doc.type;
                         data.userId = doc._id;
                         responseClient(ctx, 200, 0, '注冊成功', data);
                         return;
                     }
                 });   
             }
         })

           }

    }catch(e){
        responseClient(ctx);
    }
})

當我這樣寫的時候有時候會注冊成功有時候就會提示AssertionError [ERR_ASSERTION]: headers have already been sent

后來試了下這種寫法就沒問題

user.post('/register', async(ctx) => {
    let {username, password, rePassword} = ctx.request.body;
    
    if (!username) {
        responseClient(ctx, 400, 2, '用戶名不可為空');
        return;
    }
    if (!password) {
        responseClient(ctx, 400, 2, '密碼不可為空');
        return;
    }
    if (password !== rePassword) {
        responseClient(ctx, 400, 2, '兩次密碼不一致');
        return;
    }   

    try{
        let doc = await User.findOne({username})
        if(doc){
            responseClient(ctx, 200, 1, '用戶名已存在');
            return
        }else{
            let user = new User({
                    username: username,
                    password: password,
                    type: 'user'
                });

            let newUser = await user.save();
            let data = {};
            data.username = newUser.username;
            data.userType = newUser.type;
            data.userId = newUser._id;
            responseClient(ctx, 200, 0, '注冊成功', data);
            return;
        }

    }catch(e){
        responseClient(ctx);
    }
})

responseClient

    responseClient(ctx,httpCode = 500, code = 3,message='服務端異常',data={}) {
        let responseData = {};
        responseData.code = code;
        responseData.message = message;
        responseData.data = data;
        ctx.status = httpCode;
        ctx.body = responseData;
    }

請問第一種是我哪里寫錯了嗎?正常的寫法應該怎么寫?

圖片描述

回答
編輯回答
苦妄

User.findOne()的內容能發(fā)一下嗎?User.findOne()是不是返回Promise?你這樣寫試試:

user.post('/register', async(ctx) => {
let {username, password, rePassword} = ctx.request.body;

if (!username) {
    responseClient(ctx, 400, 2, '用戶名不可為空');
    return;
}
if (!password) {
    responseClient(ctx, 400, 2, '密碼不可為空');
    return;
}
if (password !== rePassword) {
    responseClient(ctx, 400, 2, '兩次密碼不一致');
    return;
}   

try{
   User.findOne({username}).then(function(doc,err){
        if(err){
             responseClient(ctx);
         }

         if(doc){
             responseClient(ctx, 200, 1, '用戶名已存在');
             return;  
         }else{
             //保存到數據庫
            let user = new User({
                 username: username,
                 password: password,
                 type: 'user'
             });

             user.save(function(err, doc){
                 if(err){
                     console.log(err);
                 }
                 if(doc){
                     let data = {};
                     data.username = doc.username;
                     data.userType = doc.type;
                     data.userId = doc._id;
                     responseClient(ctx, 200, 0, '注冊成功', data);
                     return;
                 }
             });   
         }
     })

       }

}catch(e){
    responseClient(ctx);
}

})

2018年3月11日 13:26
編輯回答
逗婦乳

先說錯在什么地方

if(err){
    responseClient(ctx);
    // 此處應該有return
}

err不為空時已經調用了responseClient,但是又繼續(xù)往下走,這時doc顯然是空,所以會走到else里面
,無論成功或是異常(我也不知道,因為看不到執(zhí)行結果),最后都會再執(zhí)行一次responseClient。2次調用向客戶端響應的方法,就會出現:

headers have already been sent

第一種方式有點不知所云。callback和await/async本來是二選一,為什么第一種寫法既有await又有callback?
至于正確的寫法,只能說造成問題的主要是你沒有return,后面的邏輯是否正確還要你自己執(zhí)行看看。

2018年3月10日 09:00