2016-07-16 3 views
0

ExpressJS 응용 프로그램의 Bookshelf 사용자 모델에 매우 기본적인 로그인 방법을 추가하고 있지만 User 모델의 로그인 함수가 반환하는 거부 된 오류로부터 오류를 잡을 수는 없습니다. . 나는 Books shelf의 예제 로그인을 http://bookshelfjs.org/#Model-static-extend의 docs에서보고 있지만이 예제에서는 Bluebird를 사용하고 있지만 반면에 내장 된 ES6 약속과 동일한 작업을 수행하려고합니다. 사용자 모델에서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 
} 

내 생각에 은 Bookshelf의 User.fetch 메서드가 주어진 전자 메일을 가진 사용자를 찾을 수 없을 때 거부 된 약속을 반환 할 수 있습니다. 이 경우 .catch(User.NotFoundError ...) (catch # 1) 줄이이를 catch하고 404를 반환해야합니다. 에 전달 된 암호가 사용자의 암호와 일치하지 않는다고 판단한 경우 bcrypt에서 거부 된 약속을 반환 할 수도 있습니다. 내가 잘못된 암호를 넣으면 "포괄"(2 캐치 #)를 User.NotFoundError catch 문 아래는 401

를 반환해야합니다, 위의 코드에서 logUserIn() 컨트롤러 액션 오류 메시지 { error: "Cannot set property 'message' of undefined" }과 # 2를 잡아 간다 메시지 대신 login()에 거절 한 메시지. 존재하지 않는 이메일을 넣으면 응답이 전송되지 않고 콘솔에 오류 Unhandled rejection CustomError: EmptyResponse이 표시됩니다. 유효한 입력 만 작동합니다.

수정 시도 :User.NotFoundError을 모델에 직접 붙잡고 있습니다.

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!' })); 
    }); 

이 방법은, 내가 모두 오류 (잘못된 암호를 잡을 수 : 로그인 방법은 지금처럼 보이도록

나는 사용자 모델에 캐치 # 1을 이동 존재하지 않는 전자 메일)을 올바르게 입력했는데 컨트롤러에서 상태 코드를 지정할 수 없습니다. 주어진 이메일을 가진 사용자를 찾을 수 없다면 404를 반환해야하지만 비밀번호가 틀린 경우 401을 반환해야하지만 두 오류는 모두 catch-all (catch # 2)로 이동해야합니다. 컨트롤러 동작 (항상 401을 반환).

이 문제를 해결하려면 User 모델에서 나는 .catch(User.NotFoundError,() => reject({ name: 'NotFoundError', message: 'User not found!' }))을 할 수있는 컨트롤러의 행동에 나는 const statusCode = err.name === 'NotFoundError' ? 404 : 401으로지고있어 오류의 종류를 확인할 수 있지만 정말 더러워 보인다 이러한 .catch 문을 갖는 지점이 골대를 벗어났습니다 .

에있는 모델의 로그인 방법 및 기타 오류에서 User.NotFoundError을 잡을 방법이 있습니까? 왜 내가 처음에 설치 한 설정이 usersAuthController에 catch 문을 모두 가지고있는 것은 아닙니다.js이고 Cannot set property 'message' of undefined'CustomError: EmptyResponse 오류는 무엇을 의미합니까? (이것은 Bookshelf의 Bluebird 약속을 섞어 놓는 것과 내장 된 ES6 약속을 비교하는 것과 관련이 있습니까?) 이것을 처리하는 가장 좋은 방법은 무엇입니까?

+0

이 피 ['Promise' 생성자 안티 패턴 (http://stackoverflow.com/q/23803743/1048572)! 'login' 함수 내에서만'bcrypt.compare'를 promisify해야합니다. – 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

고마워요! 그냥 명확히하기 위해 보통 Promise에서 물건을 포장해야합니까 (내가 이것을 얻으면'.then'에서 Promise를 반환하는 것이''.then''을 연결할 수 있도록하는 것입니다)? – satray

+1

@satray 무언가가 이미 약속을 반환하면 포장하지 않아도됩니다. 이 경우,'bcrypt.compare'는 약속을 반환하지 않기 때문에 래핑됩니다 (그러나 "가능한 한 늦게"). 벌써'.then()'와'.catch() '를 처리한다고해도, 약속을 돌려주는 것은 좋은 일이다. – robertklep