什么是洋葱模型
洋葱模型,就必须聊一聊中间件,中间件这个概念,我们并不陌生,比如平时我们用的 redux、express 、koa 这些库里,都离不开中间件。
那 koa 里面的中间件是什么样的呢?其本质上是一个函数,这个函数有着特定,单一的功能,koa将一个个中间件注册进来,通过组合实现强大的功能。
// index.js
const Koa = require("koa")
const app = new Koa();
// 中间件1
app.use(async (ctx, next) => {
console.log("1")
await next()
console.log("2")
});
// 中间件2
app.use(async (ctx, next) => {
console.log("3")
await next()
console.log("4")
});
// 中间件3
app.use(async (ctx, next) => {
console.log("5")
await next()
console.log("6")
});
app.listen(8002);
先后注册了三个中间件,运行一下,可以看到输出结果为:
1
3
5
6
4
2
有点疑惑是不是 怎么不是123 怎么调用了一个next() 就是135。其实这就是洋葱模型,给大家画一个流程图。
一开始我们先后注册了三个中间件,分别是中间件1,中间件2,中间件3,调用listen方法,打开对应端口的页面,触发了中间件的执行。
首先会先执行第一个中间件的 next 的前置语句,相当于 demo 里面的 console.log('1') ,当调用 next() 之后,会直接进入第二个中间件,继续重复上述逻辑,直至最后一个中间件,就会执行 next 的后置语句,然后继续上一个中间件的后置语句,继续重复上述逻辑,直至执行第一个中间件的后置语句,最后输出。
这就是洋葱模型
项目搭建
初始化package.json
npm init
// 或者
npm init -y // 不需要选择,直接默认生成package.json
搭建koa的基础服务
//安装依赖
npm install koa koa-router
app.js
const Koa = require('koa');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
// 提供了一个可以访问的get请求
router.get("/", ctx => {
ctx.body = "hello world"
})
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3000, () => {
console.log('正在监听3000端口号的服务')
})
启动 node app.js
nodemon 配置
npm install nodemon -D
npm scripts 启动命令的配置
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"start": "nodemon app.js"
},
运行 npm run start 运行项目,之后就不需要使用node命令不停的启动,来获取最新的文件内容
接口地址前缀的拼接
// http://localhost:3000/book
const router = new Router({ prefix: '/book' });
koa-router 路由模块拆分
user.js
const Router = require('koa-router');
const router = new Router()
// http://localhost:3000/book/user
router.get('/', ctx => {
ctx.body = "获取用户信息"
})
module.exports = router.routes()
app.js
const user = require('./routers/user');
router.use('/user', user);
get请求 query传参
router.get('/', ctx => {
console.log(ctx.query.id)
ctx.body = "获取用户信息"
})
koa-body 解析post参数
安装koa-body
npm install koa-body
app.js
const { koaBody } = require('koa-body');
app.use(koaBody()) // 注意摆放的顺序,因为我们koa是洋葱模型,有一个中间件的执行顺序需要注意
router.use('/user', user);
app.use(router.routes());
app.use(router.allowedMethods());
安装mongoose
npm install mongoose
mongoose连接数据库
const mongoose = require('mongoose');
// 连接mongdb数据库
mongoose.connect('mongodb://localhost/book');
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
// we're connected!
console.log('mongdb数据库连接成功')
});
添加用户
models/user.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
var userSchema = new Schema({
name: { type: String, required: true },
password: { type: String, required: true },
date: { type: Date, default: Date.now },
});
module.exports = mongoose.model('Users', userSchema, 'users');
路由中使用
router.post('/addUser', async ctx => {
let { name } = ctx.request.body;
const result = await User.find({ name });
console.log(result)
if (result.length > 0) {
ctx.body = "用户已存在"
return
}
const user = await new User(ctx.request.body).save();
if (user) {
ctx.body = "添加用户成功"
} else {
ctx.body = "添加用户失败"
}
postman调用接口
综合接口演练
const Router = require('koa-router');
const router = new Router()
const User = require('../models/user.js')
// 查找单个用户信息
router.get('/', async ctx => {
let { id } = ctx.query
let user = await User.findById(id)
console.log(user)
if (user) {
ctx.body = { code: 1, data: user }
}
})
// 添加用户
router.post('/addUser', async ctx => {
let { name } = ctx.request.body;
const result = await User.find({ name });
console.log(result)
if (result.length > 0) {
ctx.body = "用户已存在"
return
}
const user = await new User(ctx.request.body).save();
if (user) {
ctx.body = "添加用户成功"
} else {
ctx.body = "添加用户失败"
}
})
// 删除用户
router.post('/deleteUser', async ctx => {
let { id } = ctx.request.body
let user = await User.findByIdAndDelete(id)
if (user) {
ctx.body = { code: 1, msg: '删除用户成功' }
}
})
// 登录
router.post('/login', async ctx => {
// let { name } = ctx.request.body;
const result = await User.find(ctx.request.body);
console.log(result)
if (result.length > 0) {
ctx.body = "登录成功"
} else {
ctx.body = "用户名或者密码错误"
}
})
module.exports = router.routes()
只要ip、协议、端口有一个不一样,都要配置跨域