报错:UnhandledPromiseRejectionWarning

来源:7-2 HttpBasicAuth传递令牌

qq_野火燎原_0

2020-03-12

提示是在model/user.js报错:

(node:9716) UnhandledPromiseRejectionWarning: Error
    at Function.verifyEmailPassword (D:\study\island\app\model\user.js:14:13)
(node:9716) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a
catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:9716) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

我断点调试,发现是没有捕获异常,导致。可是在全局全了异常捕获,但实际上是没有去执行,不知道是怎么回事,需要怎么解决。

下面是涉及到的主要代码:
api/v1/token.js

const Router = require('koa-router')
const { TokenValidator } = require('../../validators/validator')
const { loginType } = require('../../lib/enum')
const { User } = require('../../model/user')

const router = new Router({
  prefix: '/v1/token'
})

// 获取token
router.post('/', async ctx => {
  const v = await new TokenValidator().validate(ctx)
  // 根据不同type,来处理不同的登录方式
  const type = v.get('body.type')
  switch (type) {
    case loginType.USER_EMAIL:
      emailLogin(v.get('body.account'), v.get('body.secret'))
      break;
    case loginType.USER_MINI_PROGRAM:
      break;
    default:
      break;
  }
})

async function emailLogin(account, secret) {
  const user = await User.verifyEmailPassword(account, secret)
}

module.exports = router

model/user.js

const { Model, DataTypes } = require('sequelize')
const bcrypt = require('bcryptjs');

const { sequelize } = require('../../core/db')

class User extends Model {
  static async verifyEmailPassword(email, plainPassword) {
    const user = await User.findOne({
      where: {
        email
      }
    })
    if (!user) {
      throw new global.errs.AuthFailed('账号不存在');
    }

    const correct = bcrypt.compareSync(plainPassword, user.password)
    if (!correct) {
      throw new global.errs.AuthFailed('密码不正确')
    }
    return user
  }
 }

User.init(
  {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      autoIncrement: true,
    },
    nickname: DataTypes.STRING(128),
    email: {
      type: DataTypes.STRING(128),
      unique: true
    },
    password: {
      type: DataTypes.STRING,
      set(value) {
        const salt = bcrypt.genSaltSync(10); // 10: 盐的复杂度,数字越大,密码越复杂,计算成本也越高
        const psw = bcrypt.hashSync(value, salt)
        this.setDataValue('password', psw)
      }
    },
    openid: {
      type: DataTypes.STRING(64),
      unique: true
    }
  },
  { sequelize, tableName: 'user' }
)

// 将数据模型创建到数据库
sequelize.sync({
  // force: true
})

module.exports = { User }

validators/validator.js

const { LinValidator, Rule } = require('../../core/lin-validator-v2')
const { User } = require('../model/user')
const { loginType } = require('../lib/enum')

class PositiveIntegerValidator extends LinValidator {
  constructor() {
    super()
    this.id = [
      new Rule('isInt', '需要是正整数', {
        min: 1
      })
    ]
  }
}

class RegisterValidator extends LinValidator {
  // email password1, password2, nickname
  constructor() {
    super()
    this.email = [
      new Rule('isEmail', '不符合邮箱规范')
    ]
    this.password1 = [
      new Rule('isLength', '密码至少6位,最多32位', { min: 6, max: 32 }),
      new Rule('matches', '密码不符合规范', /^[\w]{6,32}$/)
    ];
    this.password2 = this.password1
    this.nickname = [
      new Rule('isLength', '昵称长度限制在4-32位', {min: 4, max: 128})
    ]
  }

  validatePassword(vals) {
    const { password1, password2 } = vals.body
    if (password1 !== password2) {
      throw new Error('密码输入不一致')
    }
  }

  async validateEmail(vals) {
    const { email } = vals.body
    const user = await User.findOne({
      where: {
        email
      }
    })
    if (user) {
      throw new Error('邮箱已存在')
    }
  }

}

class TokenValidator extends LinValidator {
  constructor() {
    super()
    this.account = [
      new Rule('isLength', '不符合账号规范', {min: 4, max: 32})
    ]
    this.secret = [
      new Rule('isOptional'),
      new Rule('isLength', '密码长度为6-32位', {min: 6, max: 32})
    ]
  }

  validateLoginType(vals) {
    const { type } = vals.body
    if (!type) {
      throw new Error('type是必须参数')
    }
    if (!loginType.isThisType(type)) {
      throw new Error('type参数不合法')
    }
  }
}

module.exports = {
  PositiveIntegerValidator,
  RegisterValidator,
  TokenValidator
};

core/http-exception.js

class HttpException extends Error {
  constructor(msg = '服务器异常', errorCode = 10000, code = 400) {
    super()
    this.msg = msg
    this.errorCode = errorCode
    this.code = code
  }
}

class ParameterException extends HttpException {
  constructor(msg = '参数错误', errorCode = 10000) {
    super()
    this.code = 400
    this.msg = msg
    this.errorCode = errorCode
  }
}

class Success extends HttpException {
  constructor(msg = 'ok', errorCode = 200) {
    super()
    this.code = 200
    this.msg = msg
    this.errorCode = errorCode
  }
}

class NotFound extends HttpException {
  constructor(msg = '资源未找到', errorCode = 404) {
    super()
    this.code = 404
    this.msg = msg
    this.errorCode = errorCode
  }
}

class AuthFailed extends HttpException {
  constructor(msg = '授权失败', errorCode) {
    super()
    this.code = 401
    this.msg = msg
    this.errorCode = errorCode
  }
}

module.exports = {
  HttpException,
  ParameterException,
  Success,
  NotFound,
  AuthFailed
};

lib/enum.js

const isThisType = function (val) {
  for (let key in this) {
    if (this[key] === val) {
      return true
    }
  }
  return false
}
const loginType = {
  USER_MINI_PROGRAM: 100,
  USER_EMAIL: 101,
  USER_MOBILE: 102,
  ADMIN_EMAIL: 300,
  isThisType
}


module.exports = {
  loginType
}

core/db.js

const { Sequelize, Model, DataTypes } = require('sequelize');
const { database, user, password, host, port } = require('../config/config').database
const sequelize = new Sequelize(database, user, password, {
  dialect: 'mysql',
  host,
  port,
  logging: true,
  timezone: '+08:00',
  define: {
    underscored: true,
    freezeTableName: false,
    timestamps: true,
    paranoid: true
  }
})

module.exports = {
  sequelize
};

写回答

1回答

qq_野火燎原_0

提问者

2020-03-12

后面通过调试,发现这个异常,只能通过一层层地往上抛,到api路由里才可能被全局异常中件件拦截到。

具体代码如下:

api/v1/token.js:

const Router = require('koa-router')
const { TokenValidator } = require('../../validators/validator')
const { loginType } = require('../../lib/enum')
const { User } = require('../../model/user')

const router = new Router({
  prefix: '/v1/token'
})

// 获取token
router.post('/', async ctx => {
  const v = await new TokenValidator().validate(ctx)
  // 根据不同type,来处理不同的登录方式
  const type = v.get('body.type')
  switch (type) {
    case loginType.USER_EMAIL:
      try {
        await emailLogin(v.get('body.account'), v.get('body.secret'))
      } catch (error) {
        throw new global.errs.AuthFailed(error);
      }

      break;
    case loginType.USER_MINI_PROGRAM:
      break;
    default:
      throw global.errs.ParameterException('没有相应的处理函数');
  }
})

async function emailLogin(account, secret) {
  try {
    const user = await User.verifyEmailPassword(account, secret)
  } catch (error) {
    throw error
  }
}

module.exports = router

model/user.js:

const { Model, DataTypes } = require('sequelize')
const bcrypt = require('bcryptjs');

const { sequelize } = require('../../core/db')

class User extends Model {
  static async verifyEmailPassword(email, plainPassword) {
    const user = await User.findOne({
      where: {
        email
      }
    })
    console.log(global.errs);
    if (!user) {
      throw new global.errs.AuthFailed('账号不存在')
    }

    const correct = bcrypt.compareSync(plainPassword, user.password)
    if (!correct) {
      throw new global.errs.AuthFailed('密码不正确');
    }
    return user
  }
 }

User.init(
  {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      autoIncrement: true,
    },
    nickname: DataTypes.STRING(128),
    email: {
      type: DataTypes.STRING(128),
      unique: true
    },
    password: {
      type: DataTypes.STRING,
      set(value) {
        const salt = bcrypt.genSaltSync(10); // 10: 盐的复杂度,数字越大,密码越复杂,计算成本也越高
        const psw = bcrypt.hashSync(value, salt)
        this.setDataValue('password', psw)
      }
    },
    openid: {
      type: DataTypes.STRING(64),
      unique: true
    }
  },
  { sequelize, tableName: 'user' }
)

// 将数据模型创建到数据库
sequelize.sync({
  // force: true
})

module.exports = { User }

想问问,这跟老师的写法是一样的,为什么会出现这种情况,有什么好的解决办法吗,这个问题困扰我一天了

1
6
qq_野火燎原_0
回复
追梦_自由
解决了,通过try catch解决的,只是没有想明白原因是什么
2020-03-15
共6条回复

Node.js+Koa2+MySQL打造前后端分离精品项目《旧岛》

理解异步编程本质/培养面向对象思维,独立完成Node.js服务端开发

2223 学习 · 878 问题

查看课程