05-KOA框架

7/25/2022

# 1. KOA简介与入门

Koa 是⼀个新的 web 框架,由 Express 幕后的原班⼈⻢打造, 致⼒于成为web 应⽤和 API 开发领域中的⼀个更⼩、更富有表现⼒、更健壮的基⽯。 通过利⽤ async 函数,Koa 帮你丢弃回调函数,并有⼒地增强错误处理。 Koa并没有捆绑任何中间件, ⽽是提供了⼀套优雅的⽅法,帮助您快速⽽愉快地编写服务端应⽤程序。

步骤

  • 创建文件夹 codekao
  • 进入文件夹,生成项目配置文件 npm init -y
  • 安装koa: npm i koa@2.13.4 -S
  • 在codekao文件夹下,创建 01-搭建koa服务器.js

代码如下:

const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
    ctx.body = 'Hello World';
});
app.listen(3000);
1
2
3
4
5
6

运行代码:node 01-搭建koa服务器.js

通过浏览器或postman访问之:

# 2. 中间件机制

再配⼀张洋葱模型

代码如下:

const Koa = require('koa');
const app = new Koa();

// logger
app.use(async (ctx, next) => {
    console.log(1);
    await next();
    console.log(5);
    const rt = ctx.response.get('X-Response-Time ');
    console.log(`${ctx.method} ${ctx.url} -${rt}`);
});

// x-response-time
app.use(async (ctx, next) => {
    const start = Date.now();
    console.log(2);
    await next();
    console.log(4);
    const ms = Date.now() - start;
    ctx.set('X-Response-Time', `${ms}ms`);
});

// response
app.use(async ctx => {
    console.log(3);
    ctx.status = 200; //设置响应状态码
    ctx.type = 'html'; //等价于ctx.set('Content-Type ','text / html ')
    ctx.body = 'Hello World'; //设置响应体
});

app.listen(3000); //语法糖 等同于http.createServer(app.callback()).listen(3000)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

打印结果: 1 2 3 4 5

结论: 当请求开始时先通过X-Response-Time 和logger 中间件, 然后继续交给response 中间件,当⼀个中间件调⽤next() 则该函数暂停执⾏并将控制权传递给定义的下个中间件. 当在response 中间件执⾏后, 下游没有更多的中间件. 这个时候每个中间件恢复其上游⾏为

# 3. 错误监听

常⻅抛出异常和错误类型

  • 代码语法不规范造成的JS报错异常
  • 程序运⾏中发⽣的⼀些未知异常
  • HTTP错误
  • ⾃定义的业务逻辑错误

添加error全局事件侦听器

const Koa = require('koa');
const app = new Koa();

// app.use(async ctx => {
//     ctx.body = 'hello world'
// })

// 触发错误 koa帮咱们做了处理
app.use(async (ctx, next) => {
    throw new Error('未知错误');
})

//全局错误处理 后台打印
app.on('error', err => {
    console.log('全局错误处理', err.message)
})
app.listen(3000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 4. 错误处理中间件

代码如下:

const Koa = require('koa');
const app = new Koa();

// 错误处理中间件
app.use(async (ctx, next) => {
    try {
        await next();
    } catch (error) {
        // 给⽤户显示状态码
        ctx.status = error.statusCode || error.status || 500;
        //如果是ajax请求,返回的是json错误数据
        ctx.type = 'json';
        // 给⽤户显示
        ctx.body = {
            ok: 0,
            message: error.message
        };
        // 系统⽇志
        ctx.app.emit('error', error, ctx);
    }
})

// 触发错误 koa帮咱们做了处理
app.use(async (ctx, next) => {
    throw new Error('未知错误');
})

// response
//....
//全局错误处理 后台打印
app.on('error', err => {
    console.log('全局错误处理', err.message)
})
app.listen(3000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

注意: 每次修改了服务器代码,都需要重新启动服务器,为了方便,可以全局安装nodemon。

  • 全局安装:npm i nodemon -g

# 5. koa-logger处理⽇志

安装: npm i koa-logger@3.2.1

  • 尽量和我的版本保持一致
  • 在控制台可以更加细致看到错误信息
const Koa = require('koa');
const app = new Koa();
const logger = require('koa-logger')
app.use(logger())

app.use(async (ctx, next) => {
    throw new Error('未知错误');
})

// 全局的事件监听器
app.on('error', (err) => {
    console.log('全局错误处理:', err.message, err.status, err.data)
})

app.listen(3000, () => {
    console.log('3000端口被监听了~~')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 6. koa-erros处理错误

安装: npm i koa-onerror@4.2.0

  • 尽量和我的版本保持一致
  • 在控制台可以更加细致看到错误信息
const Koa = require('koa')
const onerror = require('koa-onerror')
const app = new Koa()
const logger = require('koa-logger')
app.use(logger())

onerror(app)

// koa的中间件
app.use(async (ctx, next) => {
    // ctx.throw()相当于是一个中间件
    ctx.throw(401, '未授权', {
        data: '你瞅瞅'
    })
    //   ctx.body = 'wc' //设置响应体
    /* 
    等价
        const err = new Error('未授权');
        err.status = 401;
        err.expose = true;
        throw err;
    */
})

app.use(async (ctx) => {
    ctx.body = '错误处理中间件'
})
// 全局的事件监听器
app.on('error', (err) => {
    console.log('全局错误处理:', err.message, err.status, err.data)
})

app.listen(3000, () => {
    console.log('3000端口被监听了~~')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 7. koa-log4处理⽇志

koa-log4 ⽐较好⽤的node环境下处理⽇志处理的模块, koa-log4 在 log4js-node 的基础上做了⼀次包装,是 koa 的⼀个处理⽇志的中间件,此模块可以帮助你按照你配置的规则分叉⽇志消息。

操作步骤:

  • 在根⽬录下新建 logger/ ⽬录
  • 在 logger/ ⽬录下新建 logs/ ⽬录,⽤来存放⽇志⽂件
  • 在 logger/ ⽬录下新建 index.js ⽂件

安装: npm i koa-log4@2.3.2

logger目录下的index.js代码(大家直接copy)如下:

const path = require('path')
const log4js = require('koa-log4')

log4js.configure({
    appenders: {
        //   访问级别
        access: {
            type: 'dateFile',
            // 生成文件的规则
            pattern: '-yyyy-MM-dd.log',
            // 文件名始终以日期区分
            alwaysIncludePattern: true,
            encoding: 'utf-8',
            // 生成文件路径和文件名
            filename: path.join(__dirname, 'logs', 'access')
        },
        application: {
            type: 'dateFile',
            pattern: '-yyyy-MM-dd.log',
            alwaysIncludePattern: true,
            encoding: 'utf-8',
            filename: path.join(__dirname, 'logs', 'application')
        },
        out: {
            type: 'console'
        }
    },
    categories: {
        default: {
            appenders: ['out'],
            level: 'info'
        },
        access: {
            appenders: ['access'],
            level: 'info'
        },
        application: {
            appenders: ['application'],
            level: 'WARN'
        }
    }
})

// // 记录所有访问级别的日志
// exports.accessLogger = () => log4js.koaLogger(log4js.getLogger('access'))
// // 记录所有应用级别的日志
// exports.logger = log4js.getLogger('application')

module.exports = {
    // 记录所有访问级别的日志
    accessLogger: () => log4js.koaLogger(log4js.getLogger('access')),
    // 记录所有应用级别的日志
    logger: log4js.getLogger('application')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  • 访问级别的,记录⽤户的所有请求,作为koa的中间件,直接使⽤便可。
  • 应⽤级别的⽇志,可记录全局状态下的 error ,修改 app.js 全局捕捉异常

修改对应的代码如下:

const Koa = require('koa')
const onerror = require('koa-onerror')
const {
    accessLogger,
    logger
} = require('./logger')
const app = new Koa()

onerror(app)
app.use(accessLogger())

// koa的中间件
app.use(async (ctx, next) => {
    // ctx.throw()相当于是一个中间件
    ctx.throw(401, '未授权', {
        data: '你瞅瞅'
    })
    //   ctx.body = 'wc' //设置响应体
    /* 
    等价
        const err = new Error('未授权');
        err.status = 401;
        err.expose = true;
        throw err;
    */
})

// app.use(async ctx => {
//     ctx.body = 'Hello World';
// });

// 全局的事件监听器
app.on('error', (err) => {
    logger.error(err)
})

app.listen(3000, () => {
    console.log('3000端口被监听了~~')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 8. 路由中间件koa-router

安装: npm i @koa/router@10.1.1 使⽤: 新建router/index.js和router/users.js

router/index.js中代码如下:

const Router = require('@koa/router');
const router = new Router();

router.get('/', (ctx, next) => {
    ctx.body = '⾸⻚';
})

module.exports = router;
1
2
3
4
5
6
7
8

router/user.js中代码如下:

const Router = require('@koa/router');
const router = new Router();
router.prefix('/user')

router.get('/', (ctx, next) => {
    ctx.body = '⽤户界⾯';
})

module.exports = router;
1
2
3
4
5
6
7
8
9

入口文件中导⼊并注册,如下:

const Koa = require('koa')
const index = require('./router/index')
const users = require('./router/user')

const app = new Koa()

// 注册路由
app.use(index.routes())
index.allowedMethods()
app.use(users.routes())
users.allowedMethods()

app.listen(3000, () => {
    console.log('3000端口被监听了~~')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 9. get请求

// router/user.js
const Router = require('@koa/router');
const router = new Router();
router.prefix('/user')

//访问http://localhost:3000/users/3/1
router.get('/:id/:pid', (ctx, next) => {
    console.log(ctx.params.id, ctx.params.pid);
    ctx.body = '⽤户界⾯1';
})
//访问http://localhost:3000/user/3?name=wc
router.get('/:id', (ctx, next) => {
    //通过ctx.query获取查询的参数
    console.log(ctx.query.name);
    ctx.body = '⽤户界⾯2';
})

module.exports = router;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 10. post请求

  • post解析请求的参数需要下载 koa-bodyParser
  • 安装:npm i koa-bodyparser@4.3.0
// router/index.js

const Router = require('@koa/router');
const router = new Router();

router.post('/', (ctx, next) => {
    console.log(ctx.request.body);
    ctx.body = {
        'ok': 1
    }
})

module.exports = router;
1
2
3
4
5
6
7
8
9
10
11
12
13
// 入口 js
const Koa = require('koa')
const index = require('./router/index')
const users = require('./router/user')
const bodyParser = require('koa-bodyparser')
const app = new Koa()

app.use(bodyParser());

// 注册路由
app.use(index.routes())
index.allowedMethods()
app.use(users.routes())
users.allowedMethods()

app.listen(3000, () => {
    console.log('3000端口被监听了~~')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

由于浏览器地址栏,只能发送get请求,要发送post请求,需要使用postman,如下:

# 11. 重定向

// router/index.js

const Router = require('@koa/router');
const router = new Router();

router.get('/login', ctx => {
    //判断⽤户是否处于登录状态...

    ctx.redirect('/sign-in');
    ctx.status = 301;
})
router.get('/sign-in', (ctx, next) => {
    ctx.body = '注册⻚⾯'
})

module.exports = router;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 12. 静态资源托管

  • 安装:npm i koa-static@5.0.0
  • 静态资源都放在根目录的public目录下面

代码:

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="./css/index.css">
</head>

<body>
    <h1>今天学习Koa,感觉非常爽~</h1>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* index.css */
h1 {
    color: red;
}
1
2
3
4

配置:

const Koa = require('koa')
const index = require('./router/index')
const users = require('./router/user')
const bodyParser = require('koa-bodyparser')
const static = require('koa-static');

const app = new Koa()

app.use(bodyParser());

app.use(static(__dirname + '/public'))

// 注册路由
app.use(index.routes())
index.allowedMethods()
app.use(users.routes())
users.allowedMethods()

app.listen(3000, () => {
    console.log('3000端口被监听了~~')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

效果如下:

Last Updated: 12/25/2022, 10:02:14 PM