2017-07-08 19 views
0

を停止していない私は私のバックエンドAPIの認証ルートを作成します。次の(ERR)実行

const express = require("express"); 
const jwt = require("jsonwebtoken"); 

const User = require("../models/User"); 

let router = express.Router(); 

router.post("/", (req, res, next) => { 
    const { username, phone, password } = req.body; 
    if (!(username || phone) || !password) { 
    let err = new Error("invalid parameters"); 
    err.status = 400; 
    next(err); 
    } 
    // XXX: Perhaps a better way to do this 
    let params = {}; 
    if (username) { 
    params.username = username; 
    } 
    if (phone) { 
    params.phone = phone; 
    } 
    User.findOne(params) 
    .then(user => { 
     if (!user) { 
     let err = new Error("invalid credentials"); 
     err.status = 401; 
     next(err); 
     } 
     user.checkPassword(password, (err, isMatch) => { 
     if (err) { 
      next(err); 
     } 

     if (!isMatch) { 
      console.log("we get here"); 
      let err = new Error("invalid credentials"); 
      err.status = 401; 
      next(err); 
     } 
     console.log("we also get here"); 
     res.send({ 
      token: jwt.sign(
      { 
       _id: user._id, 
       username: user.username, 
       phone: user.phone 
      }, 
      req.app.get("jwtSecret") 
     ) 
     }); 
     }); 
    }) 
    .catch(err => { 
     next(err); 
    }); 
}); 

module.exports = router; 

有効なユーザ名が、無効なパスワードを渡すとき、私は出力を得る:

we got here 
we also got here 
Error: Can't set headers after they are sent. 
    at ... 

next(err)が実行フローを停止していないため、応答が2回送信されるためです。

はなぜnext(err)実行フローを停止されていませんか?

答えて

3

あなたがnext(err)を呼び出した後、あなたはあなたの関数内returnする必要があります。

next(err)は、将来のルーティングを停止しますが、それはあなた自身の関数内の実行を停止しません。したがって、if/elseを使用するか、完了したらリターンして、自分の関数の他の部分を実行しないようにする必要があります。

個人的に、私はすべての私のasnyc操作のための約束を使用し、約束とコールバックのミックスと一致するものを使用することはありません。それで、あなたはただあなたの1つにすべてを拒絶し、漏斗することができます.catch()最後に。

しかし、あなたは約束とコールバックのあなたの混合物に固執するつもりなら、あなたはこのようなreturn文を追加することができます:あなたの代わりに使用しての約束を返すためにuser.checkPassword()の実装を変更した場合

router.post("/", (req, res, next) => { 
    const { username, phone, password } = req.body; 
    if (!(username || phone) || !password) { 
     let err = new Error("invalid parameters"); 
     err.status = 400; 
     next(err); 
     return; 
    } 
    // XXX: Perhaps a better way to do this 
    let params = {}; 
    if (username) { 
     params.username = username; 
    } 
    if (phone) { 
     params.phone = phone; 
    } 
    User.findOne(params).then(user => { 
     if (!user) { 
      let err = new Error("invalid credentials"); 
      err.status = 401; 
      throw err; 
     } 
     user.checkPassword(password, (err, isMatch) => { 
      if (err) { 
       next(err); 
       return; 
      } 

      if (!isMatch) { 
       console.log("we get here"); 
       let err = new Error("invalid credentials"); 
       err.status = 401; 
       next(err); 
       return; 
      } 
      console.log("we also get here"); 
      let token = jwt.sign({_id: user._id, username: user.username, phone: user.phone}, req.app.get("jwtSecret")) 
      res.send({token}); 
     }); 
    }).catch(err => { 
     next(err); 
    }); 
}); 

をコールバックは、あなたはコールバックとの約束を混合することなく、このようにそれを行うことができます。

router.post("/", (req, res, next) => { 
    function throwErr(msg, status) { 
     let err = new Error(msg); 
     err.status = status; 
     throw err; 
    } 

    Promise.resolve().then(() => { 
     const { username, phone, password } = req.body; 
     if (!(username || phone) || !password) { 
      throwErr("invalid parameters", 400); 
     } 
     let params = {}; 
     if (username) { 
      params.username = username; 
     } 
     if (phone) { 
      params.phone = phone; 
     } 
     return User.findOne(params).then(user => { 
      if (!user) { 
       throwErr("invalid credentials", 401); 
      } 
      return user.checkPassword(password).then(isMatch) => { 
       if (!isMatch) { 
        throwErr("invalid credentials", 401); 
       } 
       let token = jwt.sign({_id: user._id, username: user.username, phone: user.phone}, req.app.get("jwtSecret")) 
       res.send({token}); 
      }); 
     }); 
    }).catch(err => { 
     next(err); 
    }); 
}); 

throwErr()呼び出しはすべて.catch()になってしまいます。

+0

私はあなたの答えができ:)を受け入れるだろう。約束を使用する例を示すことは可能ですか?私はそれらをよく理解しておらず、このインスタンスでどのように使用できるのか興味があります。 – carloabelli

+0

@dedmass - どのデータベースを使用していますか? – jfriend00

+0

mongodb/mongoose。私はそこに約束をしていると思う。 checkPasswordメソッドは、コールバックを必要とするbcrypt.compareを使用します。 – carloabelli

関連する問題