koa-router笔记

基于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

你可能感兴趣的:(koa-router笔记)