likes
comments
collection
share

Koa 中间件使用案例,内附开源项目

作者站长头像
站长
· 阅读数 18

Koa 中间件是一个带有 context 和 next 参数的函数,该函数支持 async/await 语法,在中间件中调用 next 函数将代码的执行权交给下一个中间件,中间件的工作被 next() 分为前后两部分,next() 返回一个 Promise 对象。Koa 官方用洋葱模型来解释中间件的调用顺序,如下图所示:

Koa 中间件使用案例,内附开源项目

上图的意思是第一个中间件 next() 前面的代码最先执行,next() 后面的代码最后执行。第一个中间件调用 next() 之后第二个中间件开始工作,第二个中间件调用 next() 之后第三个中间件开始工作,第三个中间件是最后一个中间件,它不必调用 next()。当第三个中间件执行完时,第二个中间件 next() 后面的代码开始执行。比如在 Koa 应用中使用了如下的中间件:

app.use(async (context, next) => {
    try {
        await next()
    } catch (error: any) {
        context.body = `出错了,${error}`;
    }
})

app.use(async(context, next) => {
    context.set('X-Response-Time', `${new Date().getTime()}`);
    context.set({
        'Access-Control-Allow-Origin':'*',
        'Access-Control-Allow-Methods': 'GET,POST'
    })
    await next()
    console.log('finish')
})

app.use(async (context) => {
    console.log('set body')
    context.body = 'Hello Koa';
})

第一个中间件用于处理错误,它能处理后面的中间件抛出的任何错误,第二个中间件console.log('finish') 会比第三个中间件 console.log('set body') 后执行。

Koa社区拥有众多的中间件,读者可访问 github.com/koajs/koa/w… 查看

@koa/router

@koa/router是Koa的路由中间件,它支持带参数的动态路由、嵌套路由,还支持在路由上使用多个中间件。它的基本用法如下:

const app = new Koa()
const router = new Router()
router
    .get('/', (context) => {
        context.body = '我捕获根路径的get请求'
    })
    .get('/user', context => {
        context.body = '我捕获路径是/user的get请求'
    })
    .post('/user', context => {
        context.body = '我捕获路径是/user的post请求'
    })
app
    .use(router.routes())
    .use(router.allowedMethods())

动态路由

动态路由指的是在路径上携带参数,@koa/router 使用 path-to-regexp 将路径字符串转成正则表达式。动态路径的代码如下:

router
    .get('/user/:id', (context) => {
        context.body = `我捕获路径是/user/xx形式的的get请求,路径上的参数是${context.params.id}`
    })
    .get('/user/:id/:local', (context) => {
        context.body = `我捕获路径是/user/xx/yy形式的的get请求,路径上的参数是${context.params.id}${context.params.local}`
    })

嵌套路由

嵌套路由是指在路由中使用路由,前面的示例代码中所有的路由都是平级的,嵌套路由让路由有父子关系,代码如下:

const router = new Router()
const studentRouter = new Router()

studentRouter
    .get('/:id', (context) => {
        context.body = `我捕获路径为 /student/xx 形式的 get 请求`
    })

router.use('/student', studentRouter.routes(), studentRouter.allowedMethods())

app
    .use(router.routes())
    .use(router.allowedMethods())

上述代码中 studentRouter 是 router 的子路由,studentRouter 的路径上不必添加 /student 前缀。

在路由上使用多个中间件

使用多个中间件处理匹配到的路径,代码如下:

router
    .get('/user/:id', 
    async (context, next) => {
        console.log(context.params.id)
        await next()
    },
    (context) => {
        context.body = `我捕获路径为 /user/xx 形式的 get 请求`
})

上述代码使用两个中间件去处理 /user/:id,这两个中间件有不同的职责。

koa-compress

koa-compress 是一个用于数据压缩的中间件,使用它能够压缩数据提高传输速度,在 @koa/router 的基础上使用 koa-compress 代码如下:

import compress from 'koa-compress'

app
    .use(compress({
       // content_type 是 MIME 类型
        filter(content_type) {
            // 当响应的 Content-Type 中包含 text 时才压缩数据
            return /text/i.test(content_type)
        },
	// 当数据大小超过 500 bytes时压缩
        threshold: 500,
    }))
    .use(router.routes())
    .use(router.allowedMethods())

compress 除了可以配置上述代码中的 filter 和 threshold 字段,还有一些其他的配置项,访问github.com/koajs/compr… 查看更多的配置项。

koa-bodyparser

koa-bodyparser 基于 co-body 解析请求体中的数据,比如获取 POST 请求的参数,它支持 json、form、text 和 xml 类型的请求体,不支持 multipart/form-data,解析出的结果以对象的形式保存在 context.request.body 中。用法如下:

import bodyParser from 'koa-bodyparser'
router
    .post('/user', context => {
        context.body = context.request.body
    })

// 将 bodyParser 中间件放在第一个位置
app
	.use(bodyParser())
	.use(router.routes())
    	.use(router.allowedMethods())

bodyParser 有多个配置项,访问github.com/koajs/bodyp… 查看配置项详情。

koa-static

koa-static 是一个专门用来响应静态资源的中间件,客户端可能要加载很多静态资源,比如图片、CSS文件、JavaScript 文件等,单独为这些资源配置路由过于繁琐,使用 koa-static 只需要配置一个静态资源的存放目录,就能统一处理静态资源,代码如下:

import koaStatic from 'koa-static'
// 这表明静态资源存放在 Node.js 当前的工作目录,
// 访问 http://localhost:3001/package.json 将得到项目根目录的 package.json 文件
// 访问 http://localhost:3001/static/index.css 将得到项目根目录的 /static/index.css文件
app.use(koaStatic(process.cwd())) 

// 这表明静态资源存放在Node.js 当前工作目录下的 static 目录
// 访问 http://localhost:3001/index.css 将得到项目根目录的 /static/index.css文件
app.use(koaStatic(process.cwd() + '/static')) 

koaStatic 接受两个参数,第一个参数是 koa-static 服务的目录,这个目录之外的静态资源不被 koa-static 服务,第二个参数可选,访问github.com/koajs/stati… 查看第二个参数的详情。

@koa/multer

@koa/multer 是一个基于 multer 实现文件上传的中间件,处理 context-type 为multipart/form-data 的请求,能实现单文件上传和多文件上传,它将 FormData 的文本信息保存在 context.request.body 中,将文件信息保存到 context.request.file 或者 context.request.files 中,下面是一个处理单文件上传的示例:

import multer from '@koa/multer'
const upload = multer({
	dest: '/uploads' // 指定文件的保存路径
});

// 这个路由用于单文件上传
 router
    .post(
        '/upload', 
        upload.single('file'), // upload 中间件先处理,处理完再进入下一个中间件
        async (context, next) => {
            console.log('文件名:' + context.request.file.filename)
            console.log('文件路径:' + context.request.file.path)
            await next()
        }
    )

上述代码实现了单文件上传,此时文件信息保存在context.request.file中,如果是多文件上传,那么文件信息保存在context.request.files中,访问 github.com/koajs/multe… 了解 @koa/multer 更多详情。

Koa 开源项目

github.com/react-low-c…