2016-07-16 6 views
0

ExpressJSアプリケーションのBookshelf Userモデルに非常に基本的なログインメソッドを追加していますが、Userモデルのlogin関数が返すという拒否された約束からエラーをキャッチできません。私はhttp://bookshelfjs.org/#Model-static-extendのドキュメントのBookshelfのログイン例を見ていますが、その例ではBluebirdが使用されていますが、組み込みのES6の約束で同じことをしようとしています。 UserモデルでES6の約束とBookshelfJSのエラーをキャッチする

私のログイン方法:

userModel.js

function login(email, password) { 
    return new Promise((resolve, reject) => { 
    User.where('email', email) 
     .fetch({ require: true }) 
     .then(user => { 
     bcrypt.compare(password, user.get('password'), (err, matched) => { 
      if (!matched) return reject(new Error('Password didn\'t match!')); 
      resolve(user); 
     }); 
     }); 
    }); 

ログインを実装し、本棚UserモデルからUser.loginを呼び出すコントローラのアクション:

usersAuthController。 js

function logUserIn(req, res) { 
    new User().login(req.body.email, req.body.password) 
    .then(user => res.json({ message: 'Login succeeded!' })) 
    .catch(User.NotFoundError,() => res.status(404).json({ error: 'User not found!' }) // catch #1 
    .catch(err => res.status(401).json({ err: err.message })); // catch #2 
} 

私の意図は、login()はBookshelfのUser.fetchメソッドが指定された電子メールでユーザーを見つけることができない場合、拒否された約束を返すことができます。その場合、.catch(User.NotFoundError ...)(catch#1)行はそれを捕まえて404を返します。login()に渡されたパスワードがユーザのパスワードと一致しないと判断した場合、bcryptは拒否されたPromiseを返すつもりです。私は間違ったパスワードを入れた場合は、「キャッチオール」(2キャッチ#)User.NotFoundError catchステートメント以下は401

を返す必要があり、上記のコードでlogUserIn()コントローラのアクションはエラーメッセージ{ error: "Cannot set property 'message' of undefined" }と#2をキャッチするために行きますメッセージの代わりに私はlogin()で拒否しました。存在しない電子メールを入れた場合、応答は送信されず、エラーUnhandled rejection CustomError: EmptyResponseがコンソールにスローされます。有効な入力のみが有効です。

修正の試み:がモデルの代わりにUser.NotFoundErrorを直接キャッチします。

loginメソッドは、現在のように見えるように、私はUserモデルにキャッチ#1を移動:

userModel.js

function login(email, password) { 
    return new Promise((resolve, reject) => { 
    User.where('email', email) 
     .fetch({ require: true }) 
     .then(user => { 
     bcrypt.compare(password, user.get('password'), (err, matched) => { 
      if (!matched) return reject(new Error('Password didn\'t match!')); 
      resolve(user); 
     }); 
     }) 
     .catch(User.NotFoundError,() => reject({ error: 'User not found!' })); 
    }); 

この方法で、私はエラー(間違ったパスワードの両方をキャッチすることができますし、存在しない電子メール)が正しく表示されますが、この方法でコントローラにステータスコードを指定することはできません。指定された電子メールを持つユーザが見つからなかった場合は404を返すべきですが、パスワードが間違っていれば401を返すべきですが、両方のエラーは両方ともcatch-all(catch#2)にコントローラーアクション(常に401を返します)。私は.catch(User.NotFoundError,() => reject({ name: 'NotFoundError', message: 'User not found!' }))を行うことができ、コントローラのアクションで私は​​を取得していますエラーの種類を確認することができますが、それは本当に厄介なようで、これら.catch文を持っていることのポイントを見逃しUserモデルでは、この問題を解決するための

のモデルのログイン方法とその他のエラーからUser.NotFoundErrorをキャッチする方法はありますか?なぜ私は最初に働いていたセットアップ、usersControllerにcatchの両方のステートメントがあるのでしょうか?そして、Cannot set property 'message' of undefined'CustomError: EmptyResponseのエラーはどういう意味ですか(BookshelfのBluebirdの約束と組み込みのES6の約束を混ぜることと何か関係があります)?これを処理する最善の方法は何ですか?

+0

は避けてください[ 'Promise'コンストラクタアンチパターン](http://stackoverflow.com/q/23803743/1048572)!その 'login'機能では、' bcrypt.compare'だけを約束するべきです。 – Bergi

答えて

1

最初の実装では、User.fetch()によって引き起こされた拒否は伝播していません。また、User.fetch()はすでに約束を返しているので、新しい約束でそれを折り返すのはちょっとしたアンチパターンです(ただし、コールバックでしか動作しないので、約束はbcrypt.compare()にする必要があります)。

はこれを試してみてください:

function login(email, password) { 
    return User .where('email', email) 
       .fetch({ require: true }) 
       .then(user => { 
       return new Promise((resolve, reject) => { 
        bcrypt.compare(password, user.get('password'), (err, matched) => { 
        if (err)  return reject(err); 
        if (!matched) return reject(new Error('Password didn\'t match!')); 
        resolve(user); 
        }); 
       }) 
       }); 
} 
+0

ありがとう!ちょうど明確にするために、いつ私はプロミスで物を包むべきですか?(私がこれを得るならば、 '.then'でプロミスを返す点は' 'それで' 'を連鎖できるようにすることです)? – satray

+1

@satray何かが約束を返す場合、それをラップする必要はありません。この場合、 'bcrypt.compare'は約束を返さないため、ラップされます(ただし、できるだけ遅く)。既に '.then()'と '.catch()'を扱っていても、約束(と約束)を返すのは良いことです。 – robertklep

関連する問題