这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战」
代码[链接🔗]:(https://gitee.com/yang-yiming1234/koa/tree/master) 持续更新~
Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。
npm init
npm install koa
新建src文件夹 新建一个mian.js(叫什么都可以比如index.js)
const Koa = require('koa')
const app = new Koa()
app.use((ctx, next)=>{
ctx.body = 'hello'
})
const port = process.env.PORT || 8000
app.listen(port,()=>{
console.log(`server is running on ${port}`)
})
node src/main.js
启,在浏览器访问端口,
安装
npm i nodemon
package.json dev替换成别的也可以
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "nodemon ./src/main.js"
},
之后在控制台执行命令 npm run dev
就可以启动了。并且当我们改动代码,他也会自动的重启。
安装 dotenv
npm i dotenv
在根目录下新建.env文件(存一些项目配置的环境变量)
然后新建 src/config/config.default.js
const dotenv = require('dotenv')
dotenv.config()
console.log(process.env.APP_PORT)
// process node的进程
// env 环境变量
module.exports = process.env
main.js中引用
const Koa = require('koa')
// 解构出 APP_PORT
const { APP_PORT } = require('./config/config.default')
const app = new Koa()
app.use((ctx, next) => {
ctx.body = 'hello api'
})
app.listen(APP_PORT, () => {
console.log(`server is running on ${APP_PORT}`)
})
npm i koa-router
首先去npmjs的官网查看 ,好巧不巧 ,没有写。 npmjs
不要 紧的 我们再看看github上有没有 ✈️
使用步骤:
const Router = require('koa-router')
const indexRouter = new Router()
indexRouter.get('/',(ctx, next)=>{
ctx.body = 'hello index'
})
假如我们有一类uers的路由,我们需要新实例化一个 UserRouter,还有之前的IndexRouter。都写到main.js文件中并不是很好的写法。
新建router文件夹用于存放各种api
router/user.route.js
const Router = require('koa-router')
const router = new Router({prefix:'/users'})
// 会和 /users拼接
router.get('/',(ctx,next)=>{
ctx.body = 'hello users'
})
// 导出
module.exports = router
main.js
const Koa = require('koa')
const { APP_PORT } = require('./config/config.default')
const userRouter = require('./router/user.route')
const app = new Koa()
// 必须是一个函数
app.use(userRouter.routes())
app.listen(APP_PORT, () => {
console.log(`server is running on ${APP_PORT}`)
})
目的:将http服务和app业务分开
新建app文件,在其下面新建index.js 将mian.js中的实例化对象和使用router的都抽离出来
const Koa = require('koa')
const userRouter = require('./router/user.route')
const app = new Koa()
// 必须是一个函数
app.use(userRouter.routes())
module.exports = app
main.js
const { APP_PORT } = require('./config/config.default')
const app = require('./app/index')
app.listen(APP_PORT, () => {
console.log(`server is running on ${APP_PORT}`)
})
然后我们发现报错了,因为把main.js中的代码直接剪切到index.js中 涉及到了文件引用的路径层级改变的问题。
const userRouter = require('../router/user.route')
route中的处理函数这块拆分出来
新建controller文件夹,在其下面新建
user.controller.js
// 写成一个类
class UserController{
async register(ctx, next){
ctx.body = '用户注册成功'
}
}
// 导出实例化的对象
module.exports = new UserController()
user.route.js
const Router = require('koa-router')
// 引入controller
const { register } = require('../controller/user.controller')
const router = new Router({prefix:'/users'})
// 注册接口
router.post('/register',register)
// 导出
module.exports = router
使用postman测试一下
这里可以跳到其官网: koa-body
翻译一下:
一个完全特征的 koa 中间件,支持文件上传、form表单、json格式。提供了像express的bodyParser的相同功能。用于解析数据
npm i koa-body
注册中间件 /app/index.js 中添加
const KoaBody = require('koa-body')
// 在注册路由前注册
app.use(KoaBody())
添加后完整的
const KoaBody = require('koa-body')
const userRouter = require('../router/user.route')
const app = new Koa()
// 在注册路由前注册
app.use(KoaBody())
// 必须是一个函数
app.use(userRouter.routes())
module.exports = app
改写controller user.controller.js
//注意 createUser是异步函数 抽离出的service层
const { createUser } = require('../service/user.service')
class UserController {
async register(ctx, next) {
// 1.获取数据
console.log(ctx.request.body)
const { usesr_name, password } = ctx.request.body
// 2.操作数据库
const res = await createUser(usesr_name, password)
console.log(res)
// 3.返回给客户端
ctx.body = ctx.request.body
}
async login(ctx, next) {
ctx.body = '用户登录'
}
}
// 导出实例化的对象
module.exports = new UserController()
用于操作数据库处理 创建 /src/service/user.service.js
class UserService {
// 因为存入数据库 是异步的
async createUser(user_name,password){
return '写入数据库'
}
}
// 导出后 在控制器controller中使用
module.exports = new UserService()
Sequelize 是一个基于 promise 的 Node.js ORM, 目前支持 Postgres, MySQL, MariaDB, SQLite 以及 Microsoft SQL Server. 它具有强大的事务支持, 关联关系, 预读和延迟加载,读取复制等功能。
对象关系映射
可以两个一起下载
npm i mysql2 sequelize
新建 db/seq.js
const { Sequelize } = require('sequelize')
/**
* database
* username
* password
*/
const seq = new Sequelize('mine', 'root', 'root', {
host: 'localhost',
// 数据库类型
dialect: 'mysql'
})
// 返回值是一个promise对象
seq.authenticate().then(() => {
console.log('数据库连接成功')
}).catch(err => {
console.log('数据库连接失败', err)
})
module.exports = seq
可以使用node命令node src/db/seq.js
试一下连接是否成功
我们应该把链接数据库的配置变量放到.env中(不知道是什么翻看上一篇) .env
APP_PORT = 8000
MYSQL_HOST = localhost
MYSQL_PORT = 3306
MYSQL_USER = root
MYSQL_PWD = root
MYSQL_DB = mine
然后再使用node命令node src/db/seq.js
试一下连接是否成功
模型是要和表对应的,建立一个映射关系。 我们还是需要使用sequelize,这是它官网关于model的 📟介绍
// 解构出
const { Sequelize, Model, DataTypes } = require("sequelize");
// 创建的实例 参数是数据库的类型
const sequelize = new Sequelize("sqlite::memory:");
// 创建模型 define:定义 第一个参数是数据库的表名
const User = sequelize.define("user", {
// 表的字段名 DataTypes.数据类型
name: DataTypes.TEXT,
// 如果是多项配置,比如还要加表的默认值 就要写成对象
favoriteColor: {
type: DataTypes.TEXT,
defaultValue: 'green'
},
age: DataTypes.INTEGER,
cash: DataTypes.INTEGER
},{
// 这是其他模型参数
sequelize, // 我们需要传递连接实例
modelName: 'User' // 我们需要选择模型名称
});
(async () => {
// 执行创建数据库
await sequelize.sync({ force: true });
// 这里是代码
})();
modelName: 'User'
// 字符串
DataTypes.STRING // VARCHAR(255)
DataTypes.STRING(1234) // VARCHAR(1234)
DataTypes.STRING.BINARY // VARCHAR BINARY
DataTypes.TEXT // TEXTDataTypes.TEXT('tiny') // TINYTEXT
// 布尔
DataTypes.BOOLEAN // TINYINT(1)
// 数值
DataTypes.INTEGER // INTEGER
DataTypes.BIGINT // BIGINT
DataTypes.BIGINT(11) // BIGINT(11)
DataTypes.FLOAT // FLOAT
DataTypes.FLOAT(11) // FLOAT(11)
DataTypes.FLOAT(11, 10) // FLOAT(11,10)
DataTypes.DOUBLE // DOUBLE
DataTypes.DOUBLE(11) // DOUBLE(11)
DataTypes.DOUBLE(11, 10) // DOUBLE(11,10)
DataTypes.DECIMAL // DECIMAL
DataTypes.DECIMAL(10, 2) // DECIMAL(10,2)
// 日期
DataTypes.DATE // DATETIME 适用于 mysql / sqlite, 带时区的TIMESTAMP 适用于 postgresDataTypes.DATE(6) // DATETIME(6) 适用于 mysql 5.6.4+. 支持6位精度的小数秒DataTypes.DATEONLY // 不带时间的 DATE
// UUID
{ type: DataTypes.UUID, defaultValue: Sequelize.UUIDV4 // 或 Sequelize.UUIDV1}
然后再看一些常用参数
// 是否为空
allowNull: false,
// 默认值
defaultValue: true
// 主键
primaryKey: true
// 自动增长
autoIncrement: true
{
timestamps: false // 默认会为数据表 创建时间戳字段,如果添加次属性 则在创建时不添加时间戳字段
modelName: 'User' // 我们需要选择模型名称
}
可以看到多了两个字段,是时间戳。
定义模型时,你要告诉 Sequelize 有关数据库中表的一些信息. 但是,如果该表实际上不存在于数据库中怎么办? 如果存在,但具有不同的列,较少的列或任何其他差异,该怎么办?
这就是模型同步的来源.可以通过调用一个异步函数(返回一个Promise)model.sync(options)
. 通过此调用,Sequelize 将自动对数据库执行 SQL 查询. 请注意,这仅更改数据库中的表,而不更改 JavaScript 端的模型.
User.sync()
- 如果表不存在,则创建该表(如果已经存在,则不执行任何操作)User.sync({ force: true })
- 将创建表,如果表已经存在,则将其首先删除User.sync({ alter: true })
- 这将检查数据库中表的当前状态(它具有哪些列,它们的数据类型等),然后在表中进行必要的更改以使其与模型匹配.编写我们的model
新建model文件夹 在其下面新建 user.model.js
我们的model对象User中一共定义了三个字段user_name、password、is_admin(sequelize创建表会自动创建id)
// 解构出sequelize的DataTypes
const { DataTypes } = require('sequelize')
// 这是我们创建好的 连接数据库的
const seq = require('../db/seq')
// 创建模型 可以给表加前缀因为其自动化推断表名称,也可以让他不推断
const User = seq.define('User', {
// id 自动创建
user_name: {
// 去问档查看
type: DataTypes.STRING,
// 约束是否为空
allowNull: false,
// 唯一
unique: true,
comment: '用户名 唯一'
},
password: {
type: DataTypes.CHAR(64),
allowNull: false,
comment: '密码'
},
is_admin: {
// boolean 就是 tinity(1)
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: 0,
comment: '是否为管理员 0不是管理员'
}
})
// force如果之前存在这张表 会删了重建 文档:模型重建 用过后要注释掉
// User.sync({ force: true })
module.exports = User
在终端中执行命令
node src/model/user.model.js
其实是执行了一个建表语句
去看一下我们新建成的数据库
我们已经抽离出了 service层,用于写操作数据库的逻辑。
user.service.js
// 引入我们写好的model
const User = require('../model/user.model')
class UserService {
// 因为存入数据库 是异步的
async createUser(user_name,password)
// 当我们属性名和传过来的值一致的时候可以简写
// await表达式: 返回成功promise对象的值
const res = await User.create({user_name, password})
console.log(res)
// 返回到controller
return res
}
}
// 导出后 在控制器controller中使用
module.exports = new UserService()
INSERT INTO Users(id,name) VALUES (?,?)
async await
User.create({
user_name: user_name,
password: password
})
User.create({user_name,password})
controller 那么controller负责什么呐?
路由找到对应的controller后,接收传来的参数,然后调用我们的service层。
//注意 createUser是异步函数
const { createUser, getUserInfo } = require('../service/user.service')
class UserController {
async register(ctx, next) {
// 1.获取数据 注意一定传的要是JSON结构才能对request.body解构
const { user_name, password } = ctx.request.body
// 2.操作数据库 将参数传到service层
const res = await createUser(user_name, password)
console.log(res)
// 3.返回给客户端
ctx.body = {
code: 0,
messgae: '用户注册成功',
user_name: res.user_name
}
}
}
// 导出实例化的对象
module.exports = new UserController()
做到这里我们可以在postman里试一试
成功插入后会在控制台自动打印
我也打印了一下service中的res,可以看到它是这么样的一个对象
那么这就做好了吗?当然没有,根本没考虑到用户存在的情况。
再一次插入相同的值,100%会报错
Internal Server Error
服务器内部错误。
正常来说,没填写用户名肯定是不能存到数据库中的,这又是一个问题
Internal Server Error
服务器内部错误。
因此 我们需要做一些处理。
首先是合法性,什么是合法 就是传过来的参数不为空。我们需要判断传过来的参数是否为空,那么写在哪个文件里?先写到controller。 解构出参数,判断它们如果为空,返回状态码 400,并在body中返回code码(自己定义),和错误信息。
const { user_name, password } = ctx.request.body
// 合法性
if (!user_name || !password) {
console.log('用户名或密码为空', ctx.request.body)
ctx.status = 400
ctx.body = {
code: '10001',
messgae: '用户名或密码为空',
result: ''
}
}
如果我们已经有了这个用户名的存在,就不可以再注册了。
那这里其实就需要走一个查询接口,看数据库中是否存在这个用户名的用户
在service中写一个新方法
user.service.js
// 先把参数预留出来 虽然我们这次只需根据user_name查找
async getUserInfo({id,user_name,password,is_admin}){
const whereOpt = {}
// 短路运算
id && Object.assign(whereOpt,{ id }) // 不为空则添加到whereOpt中
user_name && Object.assign(whereOpt,{ user_name })
password && Object.assign(whereOpt,{ password })
is_admin && Object.assign(whereOpt,{ is_admin })
const res = await User.findOne({
attributes:['id', 'user_name', 'password','is_admin'],
where : whereOpt
})
// 可以看一下上面res 的结构
return res ? res.dataValues : null
}
controller controller中再新增一个判断,如果返回的这个对象不为空。则说明数据库中存在这个用户。注意调用getUserInfo()需要加await关键字(异步)
else if (await getUserInfo({ user_name })) {
ctx.status = 409
ctx.body = {
code: '10002',
messgae: '用户已存在',
result: ''
}
}
//注意 createUser是异步函数
const { createUser, getUserInfo } = require('../service/user.service')
class UserController {
async register(ctx, next) {
// 1.获取数据
console.log(ctx.request.body)
const { user_name, password } = ctx.request.body
// 合法性
if (!user_name || !password) {
console.log('用户名或密码为空', ctx.request.body)
ctx.status = 400
ctx.body = {
code: '10001',
messgae: '用户名或密码为空',
result: ''
}
}
// 合理性
else if (await getUserInfo({ user_name })) {
ctx.status = 409
ctx.body = {
code: '10002',
messgae: '用户已存在',
result: ''
}
}
else {
// 2.操作数据库
console.log(user_name, password, "user_name, password")
const res = await createUser(user_name, password)
console.log(res)
// 3.返回给客户端
ctx.body = {
code: 0,
messgae: '用户注册成功',
user_name: res.user_name
}
}
}
async login(ctx, next) {
ctx.body = '用户登录'
}
}
// 导出实例化的对象
module.exports = new UserController()
service完整代码
const User = require('../model/user.model')
class UserService {
// 因为存入数据库 是异步的
async createUser(user_name,password){
console.log(user_name,password,"service")
// 对象
// User.create({
// user_name: user_name,
// password: password
// })
// 当我们属性名和传过来的值一致的时候可以简写
// await表达式: 返回成功promise对象的值
const res = await User.create({user_name, password})
console.log(res,"res")
// 返回到controller
return res
}
async getUserInfo({id,user_name,password,is_admin}){
const whereOpt = {}
// 短路运算
id && Object.assign(whereOpt,{ id }) // 不为空则添加到whereOpt中
user_name && Object.assign(whereOpt,{ user_name })
password && Object.assign(whereOpt,{ password })
is_admin && Object.assign(whereOpt,{ is_admin })
const res = await User.findOne({
attributes:['id', 'user_name', 'password','is_admin'],
where : whereOpt
})
return res ? res.dataValues : null
}
}
// 导出后 在控制器controller中使用
module.exports = new UserService()
我们的校验都写在了controller中,我们想将这部分抽离出来,抽离成中间件
// 合法性
if (!user_name || !password) {
console.log('用户名或密码为空', ctx.request.body)
ctx.status = 400
ctx.body = {
code: '10001',
messgae: '用户名或密码为空',
result: ''
}
}
// 合理性
else if (await getUserInfo({ user_name })) {
ctx.status = 409
ctx.body = {
code: '10002',
messgae: '用户已存在',
result: ''
}
}
新建文件夹 middleware/user.middle.js
编写函数再把函数导出
const userValidator = async(ctx,next)=>{
const {user_name, password} = ctx.request.body
// 合法性
if (!user_name || !password) {
console.log('用户名或密码为空', ctx.request.body)
ctx.status = 400
ctx.body = {
code: '10001',
messgae: '用户名或密码为空',
result: ''
}
// 如果用户名或密码为空 就返回
return
}
// 否则放行向下执行
await next()
}
module.exports = {
userValidator,
}
导出了这个中间件,我们去哪使用那? 去router中
const Router = require('koa-router')
const { register, login } = require('../controller/user.controller')
// 引入中间件
const {userValidator} = require('../middleware/user.middleware')
const router = new Router({prefix:'/users'})
// 注册接口 先交给userValidator去验证,验证通过再交由register
router.post('/register',userValidator,register)
// 登录接口
router.post('/login', login)
// 导出
module.exports = router
然后测试一下
middleware/user.middle.js 新增一个方法,并且它用到了service的getUserInfo(),所以需要引入service。最后不要忘记导出
const { getUserInfo } = require('../service/user.service')
const verifyUser = async (ctx, next) => {
// 合理性
const { user_name } = ctx.request.body
if (await getUserInfo({ user_name })) {
ctx.status = 409
ctx.body = {
code: '10002',
messgae: '用户已存在',
result: ''
}
return
}
await next()
}
module.exports = {
userValidator,verifyUser
}
然后去我们的route文件
const Router = require('koa-router')
const { register, login } = require('../controller/user.controller')
const {userValidator,verifyUser} = require('../middleware/user.middleware')
const router = new Router({prefix:'/users'})
// 注册接口 先交给userValidator 和 verifyUser去验证,验证通过再交由register
router.post('/register',userValidator,verifyUser,register)
// 登录接口
router.post('/login', login)
// 导出
module.exports = router
再次测试一下
新建一个constant常量文件夹
err.type.js
module.exports = {
userFormateError:{
code : '10001',
message : '用户名或密码为空',
result : ''
},
userAlreadyExisted:{
code : '10002',
message : '用户已存在',
result : ''
}
}
然后我们的中间件中 user.middleware.js
再去引入这个 错误信息
const { userFormateError, userAlreadyExisted } = require('../constant/err.type')
将 ctx.body 替换成 ctx.app.emit 方法
ctx.status = 400
ctx.body = {
code: '10001',
messgae: '用户名或密码为空',
result: ''
}
替换为
// 封装了错误信息 ctx.app.emit在提示错误信息时使用
ctx.app.emit('error', userFormateError, ctx)
替换后为
const { getUserInfo } = require('../service/user.service')
const { userFormateError, userAlreadyExisted } = require('../constant/err.type')
const userValidator = async (ctx, next) => {
const { user_name, password } = ctx.request.body
// 合法性
if (!user_name || !password) {
console.log('用户名或密码为空', ctx.request.body)
// 封装了错误信息 ctx.app.emit在提示错误信息时使用
ctx.app.emit('error', userFormateError, ctx)
return
}
await next()
}
const verifyUser = async (ctx, next) => {
// 合理性
const { user_name } = ctx.request.body
const isExist = await getUserInfo({ user_name })
if (isExist) {
ctx.app.emit('error', userAlreadyExisted, ctx)
return
}
await next()
}
module.exports = {
userValidator, verifyUser
}
emit的错误事件 需要在我们的app的index.js
文件中通过app.on
进行监听
app.on('error',(err,ctx)=>{
})
刚才我们在user.middleware.js
文件中 也将状态码也删掉了,那我们在这个地方再加上。 我们在app文件夹下新建一个errHandler.js 来处理状态码。
module.exports = (err,ctx)=>{
let status =500
switch (err.code){
case '10001':
status = 400
break
case '10002':
status = 409
break
default:
status = 500
}
ctx.status = status
ctx.body = err
}
然后再在app/index.js中引入
const Koa = require('koa')
const KoaBody = require('koa-body')
const userRouter = require('../router/user.route')
const errHandler = require('./errHandler')
const app = new Koa()
// 在注册路由前注册
app.use(KoaBody())
// 必须是一个函数
app.use(userRouter.routes())
app.on('error', errHandler)
module.exports = app
我们之前存入数据库中的密码是没有经过加密的。这篇文章我们对密码进行一下加密处理。其实如果要求不是很高的话,可以使用md5进行加密。
我们这里使用另一个库bycrptjs,📢 是bycrptjs,在npmjs官网还有一个bycrpt,二者区别是bycrptjs进过了c++的编译。不需要其他的依赖,而bycrpt需要其他依赖。
npm i bycrptjs
可以看到它分为同步 和 异步。To hash a password:生成密码。To check a password:去验证这个生成的密码
这段生成密码的代码中 genSaltSync 方法,我们称它为 “加盐”。 它的加密方式大概是:
[密码:abc]-加上字符->[123abc]-通过算法加密一次->[具体变成什么样我们看不到]--再进行加盐--> 下面参数中的10就是进行了十次的加盐。
var bcrypt = require('bcryptjs');
var salt = bcrypt.genSaltSync(10);
var hash = bcrypt.hashSync("B4c0//", salt)
按照我们的封装,在user.router.js中经过校验之后才会进入到register,因此我们想要加密就需要在进入register前,进行加密。我们将加密也写到 处理中间件的文件中 :user.middleware.js
user.route.js
const {userValidator,verifyUser,cryptPassword} = require('../middleware/user.middleware')
// 注册接口 先交给userValidator去验证,验证通过再交由register
router.post('/register',userValidator,verifyUser,cryptPassword,register)
user.middleware.js
const cryptPassword = async (ctx, next) => {
// 解构出密码
const {password} = ctx.request.body
const salt = bcrypt.genSaltSync(10)
// 保存的是密文
const hash = bcrypt.hashSync(password,salt)
ctx.request.body.password = hash
await next()
}
// 导出
module.exports = {
userValidator, verifyUser, cryptPassword
}
然后我们测试一下,注册一个新用户
可以看到数据库的相应数据第密码已经经过了加密处理
密码的解密我们在下一篇文章再说,也就是在登录时进行解密。
接下来实现一下登录的验证。最好先把代码下下来再看,因为我们进行了封装处理。流程大概如下
首先,我们项目的目录结构如下
进入到路由文件中 user.router.js
。因为我们的项目结构,都是先进行校验后才会进入到login的controller中。所以在login的路由中新增 用户名和密码是否为空的校验 和 密码是否正确的校验。也就是 userValidator 和 verifyLogin。这两个方法我们写到中间件中。
const Router = require('koa-router')
const { register, login ,getTest} = require('../controller/user.controller')
const {userValidator,verifyUser,cryptPassword,verifyLogin} = require('../middleware/user.middleware')
const router = new Router({prefix:'/users'})
// 注册接口 先交给userValidator去验证,验证通过再交由register
router.post('/register',userValidator,verifyUser,cryptPassword,register)
// 登录接口
router.post('/login',userValidator,verifyLogin,login)
router.get('/test', getTest),
// 导出
module.exports = router
middleware/user.middleware.js
用户密码是否为空(这是我们之前写注册就已经写好的)
const userValidator = async (ctx, next) => {
const { user_name, password } = ctx.request.body
// 合法性
if (!user_name || !password) {
console.log('用户名或密码为空', ctx.request.body)
// 封装了错误信息 ctx.app.emit在提示错误信息时使用
ctx.app.emit('error', userFormateError, ctx)
return
}
await next()
}
用户是否存在 存在验证密码是否正确
其中bcrypt.compareSync传入两个密码作为参数,返回值为true/false。
还有具体的报错,我们写到了constant/err.type.js
中
const verifyLogin = async (ctx, next) => {
// 1.判断用户是否存在 不存在报错
const { user_name, password } = ctx.request.body
try {
const res = await getUserInfo({ user_name })
if (!res) {
console.error('用户不存在', { user_name })
ctx.app.emit('error', userUnExist, ctx)
return
}
// 2.密码是否匹配 不匹配报错
// compareSync 返回值是 true false
if (!bcrypt.compareSync(password, res.password)) {
ctx.app.emit('error', invalidPassword, ctx)
return
}
} catch (err) {
console.error(err)
return ctx.app.emit('error', userLoginError)
}
await next()
}
constant/err.type.js
userUnExist:{
code:'10004',
message:'用户不存在',
result:''
},
userLoginError:{
code:'10005',
message:'用户登录失败',
result:''
},
invalidPassword:{
code:'10006',
message:'密码不匹配',
result:''
}
因为我们的错误处理都已经写过了,并且只有错误处理都通过了,我们才会进入到login的controller中。所以只需要在这里写成功的即可
async login(ctx, next) {
const {user_name} = ctx.request.body
ctx.body = `欢迎回来${user_name}`
}