基于koa,有自己的next(洋葱模型),有点像发布订阅
用法(npmjs官网)
const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
const router = new Router()
router.get('/', (ctx, next) => {
console.log(222)
ctx.body = 'ok'
setTimeout(()=> next(), 2000)
})
router.get('/', (ctx, next) => {
console.log(333)
setTimeout(()=> next(), 1000)
})
router.get('/login', (ctx, next) => {
ctx.body = 'ok'
next()
})
router.get('/user/:id', (ctx, next) => {
console.log(ctx.params, ctx.query)
ctx.body = 'ok'
next()
})
app.use(router.routes()).use(router.allowedMethods())
app.use(async (ctx, next) => {
console.log('access by ', ctx.url)
})
app.listen('3000')
实现
/** my router */
class Layer {
constructor (method, path, fn) {
this.regexp = new RegExp('^' + path.replace(/:([^/]+)/g, '([^/?#]+)') + '$')
this.params_keys = path.match(/:([^/]+)/g)
this.method = method;
this.path = path
this.fn = fn
}
match (method, path) {
let vals = path.match(this.regexp)
if (this.method == method && vals) {
// 处理params参数
let params = {}
this.params_keys && this.params_keys.forEach((item, index) => {
params[item.substr(1)] = vals[index+1]
});
return { is_match: true, params }
}
return { is_match: false }
}
}
class Router {
constructor () {
this.middlewares = []
}
get (path, fn) {
this.middlewares.push(new Layer('GET', path, fn))
}
post (path, fn) {
this.middlewares.push(new Layer('POST', path, fn))
}
routes () {
return (ctx, next) => {
let match_router = this.middlewares.filter(middle => {
let result = middle.match(ctx.method, ctx.url)
if (result.is_match) {
ctx.params = result.params
}
return result.is_match
})
// 以中间件方式执行路由方法
match_router.reduceRight((prev, next) => {
return async () => {
if (prev.is_called == 'yes') {
throw new Error('next 只能调用一次')
}
prev.is_called = 'yes'
return await next.fn(ctx, prev)
}
}, next)()
}
}
allowedMethods () {
return (ctx, next) => {
next()
}
}
}
module.exports = Router
二级路由
// sub.js
let Router = require('../koa-router')
let router = new Router()
router.prefix('/sub')
router.get('/prat1', async (ctx, next) => {
ctx.body = 'wrong! guess again'
await next()
})
module.exports = router
// app.js
……
let sub_route = require('./routes/sub')
……
app.use(sub_route.routes(), sub_route.allowedMethods())
……
实现
/** my router */
class Layer {
constructor (method, path, fn) {
this.regexp = new RegExp('^' + path.replace(/:([^/]+)/g, '([^/?#]+)') + '$')
this.params_keys = path.match(/:([^/]+)/g)
this.method = method;
this.path = path
this.fn = fn
}
match (method, path, root) {
if (root && path.startsWith(root)) {
path = path.substr(root.length)
}
let vals = path.match(this.regexp)
if (this.method == method && vals) {
// 处理params参数
let params = {}
this.params_keys && this.params_keys.forEach((item, index) => {
params[item.substr(1)] = vals[index+1]
});
return { is_match: true, params }
}
return { is_match: false }
}
}
class Router {
constructor () {
this.middlewares = []
this.root = null
}
prefix (root) {
this.root = root
}
get (path, fn) {
this.middlewares.push(new Layer('GET', path, fn))
}
post (path, fn) {
this.middlewares.push(new Layer('POST', path, fn))
}
routes () {
return (ctx, next) => {
let match_router = this.middlewares.filter(middle => {
let result = middle.match(ctx.method, ctx.url, this.root)
if (result.is_match) {
ctx.params = result.params
}
return result.is_match
})
// 以中间件方式执行路由方法
match_router.reduceRight((prev, next) => {
return async () => {
if (prev.is_called == 'yes') {
throw new Error('next 只能调用一次')
}
prev.is_called = 'yes'
return await next.fn(ctx, prev)
}
}, next)()
}
}
allowedMethods () {
return (ctx, next) => {
next()
}
}
}
module.exports = Router
网友评论