Koa

161 阅读3分钟

什么是洋葱模型

洋葱模型,就必须聊一聊中间件,中间件这个概念,我们并不陌生,比如平时我们用的 reduxexpresskoa 这些库里,都离不开中间件。

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。其实这就是洋葱模型,给大家画一个流程图。

QQ截图20230504103621.png

一开始我们先后注册了三个中间件,分别是中间件1,中间件2,中间件3,调用listen方法,打开对应端口的页面,触发了中间件的执行。

首先会先执行第一个中间件的 next 的前置语句,相当于 demo 里面的 console.log('1') ,当调用 next() 之后,会直接进入第二个中间件,继续重复上述逻辑,直至最后一个中间件,就会执行 next 的后置语句,然后继续上一个中间件的后置语句,继续重复上述逻辑,直至执行第一个中间件的后置语句,最后输出。

QQ截图20230504104708.png 这就是洋葱模型

项目搭建

初始化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 = "获取用户信息"
})

image.png

koa-body 解析post参数

image.png

安装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 = "添加用户失败"
    }

image.png

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、协议、端口有一个不一样,都要配置跨域