Node.js koa2中间件开发

koa2中间件开发

koa2 中间件机制

Koa 是一个简单、轻量的 Web 框架。Koa 的最大特色,也是最重要的一个设计,就是中间件(middleware) 。Koa 应用程序是一个包含一组中间件函数的对象,它是按照类似堆栈的方式组织和执行的。Koa中使用 app.use() 用来加载中间件,基本上Koa 所有的功能都是通过中间件实现的。每个中间件默认接受两个参数,第一个参数是 Context 对象,第二个参数是next函数。只要调用next函数,就可以把执行权转交给下一个中间件。

下图为经典的Koa洋葱模型

koa2洋葱模型

看看官网的经典示例:

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
const Koa = require('koa')
const app = new Koa()

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

// logger
app.use(async (ctx, next) => {
const start = Date.now()
await next()
const ms = Date.now() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}`)
})

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

app.listen(3000)

上面的执行顺序就是:请求 ==> response-time中间件 ==> logger中间件 ==> 响应中间件 ==> logger中间件 ==> response-time中间件 ==> 响应。

请求进来,先进到x-response-time中间件,执行 const start = new Date()然后遇到await next(),则暂停x-response-time中间件的执行,跳转进logger中间件,同理,最后进入响应中间件,响应中间件中没有await next()代码,则开始逆序执行,也就是再先是回到logger中间件,执行await next()之后的代码,执行完后再回到x-response-time中间件执行await next()之后的代码。

koa2 中间件编写

我们来看看如何编写中间件,其实上面的logger、x-response-time都是中间件,通过app.use注册,同时为该函数传入 ctxnext 两个参数。

ctx 作为上下文使用,包含了基本的 ctx.requestctx.response,还对 Koa 内部对一些常用的属性或者方法做了代理操作,使得我们可以直接通过 ctx 获取。比如,ctx.request.url 可以写成 ctx.url

next 参数的作用是将处理的控制权转交给下一个中间件,而 next() 后面的代码,将会在下一个中间件及后面的中间件运行结束后再执行。

1
2
3
4
5
6
7
// middleware/logger.js
module.exports = function () {
return async function ( ctx, next ) {
console.log( ctx.method, ctx.header.host + ctx.url )
await next()
}
}

消息闪现中间件

前面我们实现了用户登录注册,但是没有一个友好的提示如:注册成功、登陆成功等。一般一个操作完成后,我们都希望在页面上闪出一个消息,告诉用户操作的结果。其原先是出自 rails 的,用于在页面上显示一些提示信息。

我们就来实现一个基于session的消息闪现。新建middlewares目录,并建一个flash.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = function flash (opts) {
let key = 'flash'
return async (ctx, next) => {
if (ctx.session === undefined) throw new Error('ctx.flash requires sessions')
let data = ctx.session[key]
ctx.session[key] = null
Object.defineProperty(ctx, 'flash', {
enumerable: true,
get: () => data,
set: (val) => {
ctx.session[key] = val
}
})
await next()
}
}

这个flash消息就是将消息挂到session上再清空,只显示一次,刷新后就没有了。这个中间件可优化的地方还很多,这儿重点不是优化功能就先跳过。

我们还需添加一个显示提示的视图模板,就叫他notification.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// components/notification.html

{% if ctx.flash %}
<div class="notifications">
{% if ctx.flash.success %}
<div class="notification is-success">
{{ctx.flash.success}}
</div>
{% elif ctx.flash.warning %}
<div class="notification is-warning">
{{ctx.flash.warning}}
</div>
{% endif %}
</div>
{% endif %}

这个模板中,添加了success和warning两种提示。把它引入base.html

使用flash中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// index.js
...
const flash = require('./middlewares/flash')
...
app.use(flash())
...

// user.js
...
signout (ctx, next) {
ctx.session.user = null
ctx.flash = { warning: '退出登录' }
ctx.redirect('/')
}
...

Node.js koa2中间件开发
https://www.xysdavid.cn/2023/12/07/Node-js-koa2中间件开发/
作者
xysDavid
发布于
2023年12月7日
许可协议