2017-01-24 3 views
1

をクリアするために、私は、JSは、この記事で約束についての質問を:私はより良い約束をやっているが、それでも種類の間違った...もう一つは

I'm doing Promises wrong... What am I missing here?

そして何かを思い付いたこと私が持っていた問題を克服するのを手伝ってください。しかし、今私はもう少し疑問があります。まだまだ謎です。

login.ts:

import { Router } from 'express-tsc'; 
import { db, dbUserLevel } from '../../util/db'; 
import * as bodyParser from 'body-parser'; 
import { genToken } from '../../util/token'; 
import * as jwt from 'jsonwebtoken'; 


export var router = Router(); 

let urlencodedParser = bodyParser.urlencoded({ extended: false }); 
let jsonParser = bodyParser.json(); 


router.post('/', jsonParser, (req, res) => { 

    req.accepts(['json', 'text/plain']); 
    let data = req.body; 
    console.log(data); 

    let username: string = data["username"]; 
    let password: string = data["password"]; 

    genToken(username, password) 
     .then(token => { 
      res.status(200).send(token); 
     }) 
     .catch(err => { 
      res.status(500).send(err); 
     }); 

}); 

私が今抱えている問題は、以下のスニペットのコメントコードで記述されています

私が持って更新されたコードで

token.ts:

import * as jwt from 'jsonwebtoken'; 
import { db, dbUserLevel } from '../util/db'; 


export function genToken(username, password) { 

    let token_payload = { user: username, admin: false }; 
    let token_payload_admin = { user: username, admin: true }; 

    // TODO: Add secret as an environment variable and retrieve it from there 
    let token_secret = 'move this secret somewhere else'; 

    let token_header = { 
     issuer: 'SomeIssuer', 
     algorithm: 'HS256', 
     expiresIn: '1h' 
    }; 

    let token: Object; 

    let query = db.open() 
     .then(() => dbUserLevel('user')) 

     // If above is successful, this .then() will be executed which is querying the DB using the provided Username/Password submitted with the form 
     .then(() => db.collection('users').findOne({ username: username, password: password }) 

      // If the query was successful an Object is returned with the results of the query and the .then() below is executed to analyze the result 
      .then((result) => { 
       if (result.isAdmin === 1) { 

        // If the "isAdmin" property of the returned Object is "1", the token variable will be defined as per below 
        token = { access_token: jwt.sign(token_payload_admin, token_secret, token_header) } 
       } else if (result.isAdmin === 0) { 

        // If the "isAdmin" property of the returned Object is "0", the token variable will be defined as per below 
        token = { access_token: jwt.sign(token_payload, token_secret, token_header) } 
       } 
      }) 

      // The question is here... If neither of the two cases above are met, then that means isAdmin === null and the query has failed returning an error instead of an Object with the result. 
      // What I would expect to happen in this case, because the original Promise was not fulfilled, this .catch() should be called. 
      // Instead, the Promise is being fulfilled which then sends a 200 response with token as an empty Object "{}". 
      // How do I get this .catch() to reject the Promise and send the 500 response instead? 

      .catch(err => { 
       db.close(); 
       Promise.reject(err); 
      })) 
     .then(() => { 
      db.close(); 
      Promise.resolve(token); 
      return token; 
     }) 
     .catch(err => { 
      db.close(); 
      Promise.reject(err); 
      return err; 
     }); 

    return query; 
}; 
+0

'Promise.reject(err)'と 'Promise.resolve(token)'ではなく 'throw err'と' return token'をそれぞれ使用してください。 – zzzzBov

答えて

4

あなたの問題は、コールバックからPromise.reject(…)returnに届かなかったことです。彼らは未処理の約束の拒否ログを生成するだけですが、コールバックはundefinedを返し、新しい結果となり、エラーが処理されることを意味します。したがって、catchコールバックは実行されません。

しかし、このコードは、とにかく単純化する必要があります。データベース接続の終了に関しては、disposer patternまたはa finally methodを見てください。

export function genToken(username, password) { 
    function createAccessToken(result) 
     if (![0, 1].includes(result.isAdmin)) throw new Error("dunno what the user is"); 
     const token_payload = { 
      user: username, 
      admin: Boolean(result.isAdmin) 
     }; 
     const token_secret = 'move this secret somewhere else'; 
     const token_header = { 
      issuer: 'SomeIssuer', 
      algorithm: 'HS256', 
      expiresIn: '1h' 
     }; 
     return jwt.sign(token_payload, token_secret, token_header); 
    } 

    return db.open() 
    .then(() => dbUserLevel('user')) 
    .then(() => db.collection('users').findOne({ username: username, password: password })) 
    .then(result => ({access_token: createAccessToken(result)})) 
    .then(token => { 
     db.close(); 
     return token; 
    }, err => { 
     db.close(); 
     throw err; 
    }); 
} 
+0

この例をお寄せいただきありがとうございます!より一般的に言えば、より良いコードを書く方法について、私に良いアイデアをくれました!それは私にはいつも感謝しています!しかし、私はこのエラーメッセージ "if(![0、1] .includes(result.isAdmin))を表示することを期待するはずですか? ");" ?悪質な資格情報を渡すと、私は500(実際には401に変更しました)をトリガーすることができますが、レスポンスにはこのメッセージは含まれません。代わりに、HTTPステータスコードを処理して、メッセージングクライアント側を処理していますが、これは問題ありません。 –

+0

数値の代わりに 'result.isAdmin'(あるいは' result'全体の?)が 'null'となることがあると理解しました。それはエラーを取得するときです。しかし、多分私は何かを欠いている? – Bergi

+0

いいえ、あなたが正しいです!ユーザー名/パスワードの照合のための照合dbの照会。 db内のすべてのユーザーは、 "isAdmin" 0または1を持ちます。照会が実行されisAdmin === nullの場合、照会はユーザー名/パスワードと一致するレコードを見つけることができませんでした。あなたが提供したもので、そのエラーがスローされたときに、「ユーザーが何を知っているのか」がどこにスローされますか?私はそれがクライアントに返された応答に含まれていましたが、クライアントに送信された応答は空のObject '{}'にすぎません。なぜそれが分かっていますか?あなたがより多くの情報を必要とするかどうか私に教えてください。 –

関連する問題