node koa
Posted Jay_帅小伙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了node koa相关的知识,希望对你有一定的参考价值。
一. 项目的初始化
1 npm 初始化
npm init -y
生成package.json
文件:
- 记录项目的依赖
2 git 初始化
git init
生成’.git’隐藏文件夹, git 的本地仓库
3 创建 ReadMe 文件
二. 搭建项目
1 安装 Koa 框架
npm install koa
2 编写最基本的 app
创建src/main.js
const Koa = require('koa')
const app = new Koa()
app.use((ctx, next) =>
ctx.body = 'hello world'
)
app.listen(3000, () =>
console.log('server is running on http://localhost:3000')
)
3 测试
在终端, 使用node src/main.js
三. 项目的基本优化
1 自动重启服务
安装 nodemon 工具
npm i nodemon -D
编写package.json
脚本
"scripts":
"dev": "nodemon ./src/main.js",
"test": "echo \\"Error: no test specified\\" && exit 1"
,
执行npm run dev
启动服务
2 读取配置文件
安装dotenv
, 读取根目录中的.env
文件, 将配置写到process.env
中
npm i dotenv
创建.env
文件
APP_PORT=8000
创建src/config/config.default.js
const dotenv = require('dotenv')
dotenv.config()
// console.log(process.env.APP_PORT)
module.exports = process.env
改写main.js
const Koa = require('koa')
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 http://localhost:$APP_PORT`)
)
四. 添加路由
路由: 根据不同的 URL, 调用对应处理函数
1 安装 koa-router
npm i koa-router
步骤:
- 导入包
- 实例化对象
- 编写路由
- 注册中间件
2 编写路由
创建src/router
目录, 编写user.route.js
const Router = require('koa-router')
const router = new Router( prefix: '/users' )
// GET /users/
router.get('/', (ctx, next) =>
ctx.body = 'hello users'
)
module.exports = router
3 改写 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 http://localhost:$APP_PORT`)
)
五. 目录结构优化
1 将 http 服务和 app 业务拆分
创建src/app/index.js
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')
app.listen(APP_PORT, () =>
console.log(`server is running on http://localhost:$APP_PORT`)
)
2 将路由和控制器拆分
路由: 解析 URL, 分布给控制器对应的方法
控制器: 处理不同的业务
改写user.route.js
const Router = require('koa-router')
const register, login = require('../controller/user.controller')
const router = new Router( prefix: '/users' )
// 注册接口
router.post('/register', register)
// 登录接口
router.post('/login', login)
module.exports = router
创建controller/user.controller.js
class UserController
async register(ctx, next)
ctx.body = '用户注册成功'
async login(ctx, next)
ctx.body = '登录成功'
module.exports = new UserController()
六. 解析 body
1 安装 koa-body
npm i koa-body
2 注册中间件
改写app/index.js
3 解析请求数据
改写user.controller.js
文件
const createUser = require('../service/user.service')
class UserController
async register(ctx, next)
// 1. 获取数据
// console.log(ctx.request.body)
const user_name, password = ctx.request.body
// 2. 操作数据库
const res = await createUser(user_name, password)
// console.log(res)
// 3. 返回结果
ctx.body = ctx.request.body
async login(ctx, next)
ctx.body = '登录成功'
module.exports = new UserController()
4 拆分 service 层
service 层主要是做数据库处理
创建src/service/user.service.js
class UserService
async createUser(user_name, password)
// todo: 写入数据库
return '写入数据库成功'
module.exports = new UserService()
七. 集成 sequlize
sequelize ORM 数据库工具
ORM: 对象关系映射
- 数据表映射(对应)一个类
- 数据表中的数据行(记录)对应一个对象
- 数据表字段对应对象的属性
- 数据表的操作对应对象的方法
1 安装 sequelize
npm i mysql2 sequelize
2 连接数据库
src/db/seq.js
const Sequelize = require('sequelize')
const
MYSQL_HOST,
MYSQL_PORT,
MYSQL_USER,
MYSQL_PWD,
MYSQL_DB,
= require('../config/config.default')
const seq = new Sequelize(MYSQL_DB, MYSQL_USER, MYSQL_PWD,
host: MYSQL_HOST,
dialect: 'mysql',
)
seq
.authenticate()
.then(() =>
console.log('数据库连接成功')
)
.catch((err) =>
console.log('数据库连接失败', err)
)
module.exports = seq
3 编写配置文件
APP_PORT = 8000
MYSQL_HOST = localhost
MYSQL_PORT = 3306
MYSQL_USER = root
MYSQL_PWD = 123456
MYSQL_DB = zdsc
八. 创建 User 模型
1 拆分 Model 层
sequelize 主要通过 Model 对应数据表
创建src/model/user.model.js
const DataTypes = require('sequelize')
const seq = require('../db/seq')
// 创建模型(Model zd_user -> 表 zd_users)
const User = seq.define('zd_user',
// id 会被sequelize自动创建, 管理
user_name:
type: DataTypes.STRING,
allowNull: false,
unique: true,
comment: '用户名, 唯一',
,
password:
type: DataTypes.CHAR(64),
allowNull: false,
comment: '密码',
,
is_admin:
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: 0,
comment: '是否为管理员, 0: 不是管理员(默认); 1: 是管理员',
,
)
// 强制同步数据库(创建数据表)
// User.sync( force: true )
module.exports = User
九. 添加用户入库
所有数据库的操作都在 Service 层完成, Service 调用 Model 完成数据库操作
改写src/service/user.service.js
const User = require('../model/use.model')
class UserService
async createUser(user_name, password)
// 插入数据
// User.create(
// // 表的字段
// user_name: user_name,
// password: password
// )
// await表达式: promise对象的值
const res = await User.create( user_name, password )
// console.log(res)
return res.dataValues
module.exports = new UserService()
同时, 改写user.controller.js
const createUser = require('../service/user.service')
class UserController
async register(ctx, next)
// 1. 获取数据
// console.log(ctx.request.body)
const user_name, password = ctx.request.body
// 2. 操作数据库
const res = await createUser(user_name, password)
// console.log(res)
// 3. 返回结果
ctx.body =
code: 0,
message: '用户注册成功',
result:
id: res.id,
user_name: res.user_name,
,
async login(ctx, next)
ctx.body = '登录成功'
module.exports = new UserController()
十. 错误处理
在控制器中, 对不同的错误进行处理, 返回不同的提示错误提示, 提高代码质量
const createUser, getUerInfo = 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.error('用户名或密码为空', ctx.request.body)
ctx.status = 400
ctx.body =
code: '10001',
message: '用户名或密码为空',
result: '',
return
// 合理性
if (getUerInfo( user_name ))
ctx.status = 409
ctx.body =
code: '10002',
message: '用户已经存在',
result: '',
return
// 2. 操作数据库
const res = await createUser(user_name, password)
// console.log(res)
// 3. 返回结果
ctx.body =
code: 0,
message: '用户注册成功',
result:
id: res.id,
user_name: res.user_name,
,
async login(ctx, next)
ctx.body = '登录成功'
module.exports = new UserController()
在 service 中封装函数
const User = require('../model/use.model')
class UserService
async createUser(user_name, password)
// 插入数据
// await表达式: promise对象的值
const res = await User.create( user_name, password )
// console.log(res)
return res.dataValues
async getUerInfo( id, user_name, password, is_admin )
const whereOpt =
id && Object.assign(whereOpt, id )
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
module.exports = new UserService()
十一. 拆分中间件
为了使代码的逻辑更加清晰, 我们可以拆分一个中间件层, 封装多个中间件函数
1 拆分中间件
添加src/middleware/user.middleware.js
const getUerInfo = require('../service/user.service')
const userFormateError, userAlreadyExited = require('../constant/err.type')
const userValidator = async (ctx, next) =>
const user_name, password = ctx.request.body
// 合法性
if (!user_name || !password)
console.error('用户名或密码为空', ctx.request.body)
ctx.app.emit('error', userFormateError, ctx)
return
await next()
const verifyUser = async (ctx, next) =>
const user_name = ctx.request.body
if (getUerInfo( user_name ))
ctx.app.emit('error', userAlreadyExited, ctx)
return
await next()
module.exports =
userValidator,
verifyUser,
2 统一错误处理
- 在出错的地方使用
ctx.app.emit
提交错误 - 在 app 中通过
app.on
监听
编写统一的错误定义文件
module.exports =
userFormateError:
code: '10001',
message: '用户名或密码为空',
result: '',
,
userAlreadyExited:
code: '10002',
message: '用户已经存在',
result: '',
,
3 错误处理函数
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 errHandler = require('./errHandler')
// 统一的错误处理
app.on('error', errHandler)
十二. 加密
在将密码保存到数据库之前, 要对密码进行加密处理
123123abc (加盐) 加盐加密
1 安装 bcryptjs
npm i bcryptjs
2 编写加密中间件
const crpytPassword = async (ctx, next) =>
const password = ctx.request.body
const salt = bcrypt.genSaltSync(10)
// hash保存的是 密文
const hash = bcrypt.hashSync(password, salt)
ctx.request.body.password = hash
await next()
3 在 router 中使用
改写user.router.js
const Router = require('koa-router')
const
userValidator,
verifyUser,
crpytPassword,
node-koa-路由传值