最近因为开发一个自己的博客网站,学习了koa2的搭建,写了一些自己认为比较重要或需要知道的koa2中间件作用和使用场景。
koa-router
路由中间件
下载
使用
普通使用方法
需要注意的是引入的koa-router是一个方法,引入后需要执行这个方法。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
const Koa = require( 'koa' );
const app = new Koa();
const router = require( 'koa-router' )();
router.get( '/' , async (ctx, next) => {
ctx.body = 'Hello World' ;
});
router.get( '/hello/:name' , async (ctx, next) => {
var name = ctx.params.name;
ctx.response.body = \`<h1>Hello, ${name}!</h1>\`;
});
app.use(router.routes(), router.allowedMethods());
|
也可以按需引入并注册路由,可注册多个路由。
不同请求下接收的参数获取
router.get
通过ctx.query获取参数
router.post
通过ctx.request.body获取参数
动态路由 router.get('/:id', func)
通过ctx.params获取参数
遍历注册router
首先引入nodejs中的fs模块,使用fs的readdirSync方法获取到指定目录的所有文件名,遍历引入路由模块并注册。
const fs = require('fs');
?
1
2
3
4
5
|
fs.readdirSync( './routes' ).forEach(route=> {
let api = require(\`./routes/${route}\`);
app.use(api.routes(), api.allowedMethods());
});
|
koa-router中的其它api
router.prefix(prefix) 添加url前缀
设置已经初始化的路由器实例的路径前缀
?
1
2
3
4
5
6
|
router.prefix( '/user' );
router.post( '/login' , function (ctx, next) {
...
});
|
router.use(url|[url1,url2,...], (ctx, next) => {...}) 路由中间件
使用场景:我们通常需要通过验证用户和用户权限来判定用户是否能使用该接口,如果在每个接口都写一次验证非常麻烦且不好维护。这时我们就需要路由中间件先进行验证,再执行下面操作。
router.use的第一个参数为一个路径或者由多个需要使用中间件的路径组成的数组(需要注意的是,如果路由设置了url前缀,需要在设置前缀后注册中间件,参数中的url不需要设置前缀)。
router.use的第二个参数为函数,函数传递ctx和next两个参数,可通过ctx进行权限验证后,判断是否执行next调用接口。这里特别需要注意的是函数使用next的时候需要添加await,如果不添加,在调用接口前,接口就会返回结果,前台则无法获取到数据。
?
1
2
3
4
5
6
7
8
9
10
|
app.use( function (ctx, next) {
ctx.set( "Access-Control-Allow-Origin" , "\*" );
next();
});
app.use(async function (ctx, next) {
ctx.set( "Access-Control-Allow-Origin" , "\*" );
await next();
});
|
koa-bodyparser处理post请求
处理post请求时,我们会遇到一个问题,无论是node的request对象还是koa的request对象,都没办法解析request的body,我们就需要下载并引入一个解析body的中间件koa-bodyparser,koa-bodyparser的具体配置详见下面的说明,这里我们直接放入使用方式。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
const index = require( './routes/index.js' );
const user = require( './routes/user.js' );
const bodyparser = require( 'koa-bodyparser' );
app.use(bodyparser({
enableTypes:\[ 'json' , 'form' , 'text' \]
}));
...
app.use(index.routes(), index.allowedMethods());
app.use(user.routes(), user.allowedMethods());
|
koa-bodyparser
如上所述,koa-bodyparser用于解析request.body,因为node和koa的request无法解析body。
下载
使用
?
1
|
const bodyparser = require( 'koa-bodyparser' );
|
在注册运行时,bodyparser方法中可传入对象,作相应配置。
- enableTypes:解析器只在配置了enableTypes时解析请求类型,默认是['json', 'form']。
- encoding:请求编码,默认是utf-8。
- formLimit:urlencoded body的imit如果主体最终大于此限制,则返回一个413错误代码。默认是56 kb。
- jsonLimit:json主体的限制。默认是1 mb。
- textLimit:文本主体的限制。默认是1 mb。
- strict:当设置为true时,JSON解析器将只接受数组和对象。默认是正确的。参见正文中的严格模式。在严格模式下,ctx.request。body总是一个对象(或数组),这避免了很多类型判断。但文本正文总是返回字符串类型。
- detectJSON:自定义json请求检测函数。默认为null。
?
1
2
3
4
5
|
app.use(bodyparser({
detectJSON: function (ctx) {
return /\\.json$/i.test(ctx.path);
}
}));
|
- extendTypes:支持扩展类型
?
1
2
3
4
5
|
app.use(bodyparser({
extendTypes: {
json: \[ 'application/x-javascript' \]
}
}));
|
- onerror:支持自定义错误句柄,如果koa-bodyparser抛出一个错误,您可以自定义响应如下:
?
1
2
3
4
5
|
app.use(bodyparser({
onerror: function (err, ctx) {
ctx. throw ( 'body parse error' , 422);
}
}));
|
- disableBodyParser:可以通过设置ctx动态禁用body解析器。disableBodyParser = true。
?
1
2
3
4
5
|
app.use(async (ctx, next) => {
if (ctx.path === '/disable' ) ctx.disableBodyParser = true ;
await next();
});
app.use(bodyparser());
|
koa-logger
请求响应监听日志
下载
使用
?
1
2
3
4
5
|
~~
const logger = require( 'koa-logger' );
app.use(logger()); ~~
|
koa-session
用于Koa的简单会话中间件。默认为基于cookie的会话,并支持外部存储。
session
我们知道,http协议是无状态的,当用户进行登录后,并不会保存账户密码,如果我们需要维持用户的登录状态,就需要使用一些方法。目前主流的用户认证方法有基于token和基于session两种方式。
基于token的认证可以使用koa-jwt中间件,基于session的认证则使用标题的koa-session。
下载
使用
app.js 入口文件中注册session
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
const CONFIG = {
key: 'koa:sess' , /\*\* (string) cookie key ( default is koa:sess) \*/
/\*\* (number || 'session' ) maxAge in ms ( default is 1 days) \*/
maxAge: 86400000,
autoCommit: true , /\*\* (boolean) 自动保存头部 ( default true ) \*/
overwrite: true , /\*\* (boolean) 能否覆盖 ( default true ) \*/
httpOnly: true , /\*\* (boolean) httpOnly or not ( default true ) \*/
signed: true , /\*\* (boolean) signed or not ( default true ) \*/
/\*\* (boolean) 强制在每个响应上设置会话标识符cookie。过期将重置为原始maxAge,重新设置过期倒计时。 ( default is false ) \*/
rolling: false ,
/\*\* (boolean) 当会话快过期时续订会话,这样我们可以始终保持用户登录。( default is false )\*/
renew: false ,
};
app.use(session(sessionConfig, app));
|
session的使用
注册后可以通过上下文ctx找到session属性,下面代码将用户信息存入session属性中,并创建key和value
user.js
?
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
|
static async login(ctx, next) {
const data = ctx.request.body
const schema = Joi.object().keys({
username: Joi.string().required(),
password: Joi.string().required(),
})
let result = Joi.validate(data, schema)
if (result.error) {
return ctx.response.body = { status: 400, msg: result.error.details};
}
let { username, password } = result.value
const userInfo = await usersModel.findByName(username)
if (userInfo) {
const userInfo2 = await usersModel.findOne({ username, password })
if (userInfo2) {
ctx.response.body = {state: 200, msg: '登录成功' }
ctx.session.userInfo = userInfo2
} else {
ctx.response.body = {state: 410, msg: '密码错误' }
}
} else {
ctx.response.body = {state: 410, msg: '该用户不存在' }
}
return ctx.response.body
}
|
koa-router路由中间件中验证session,这里需要注意的是next()方法前一定要使用await,不然程序不会等待next()方法执行。
?
1
2
3
4
5
6
7
8
|
export const verifyUser = async (ctx, next) => {
if (ctx.session.userInfo) {
await next()
} else {
return ctx.response.body = { state: 401, msg: '无权限访问' }
}
}
|
koa2-cors
用于解决跨域问题
下载
使用