Node web 框架 - Express ( 200行实现基础功能,理解原理 )

 Express 框架是基于 http 做一个一个 web 框架

  

  具体做什么呢?

  1、对 request 、response 进行封装,实现了一些方便简洁的方法

  2、实现了 app.use 对 request 、response 进行处理

  3、实现了 get 、post 等方法实现路由返回响应值的值

  4、另外一些 render 等方法实现了使用模板引擎渲染页面

 

  下面使用了 200 行代码展示了 use / get / post 的实现

const http = require('http')
const regExpCompile = require('path-to-regexp')
class Route {
    constructor(option) {
        // methods,path
        Object.assign(this, option)
        this.stack = []

    }

    addLayer(method, handle) {
        const layer = {
            method,
            handle,
        }
        this.stack.push(layer)
    }

    dispatch(req, res, next) {
        const {stack} = this;
        const match = false;
        const layer = null
        const {method} = req
        let id = 0
        let handle = null

        while (!handle && id < stack.length) {
            const layer = stack[id++]
            if (method.toLowerCase() === layer.method) {
                handle = layer.handle
                continue
            }
        }
        if (!handle) next && next()
        handle(req, res, next)
    }
}
class Layer {
    constructor(option, fn) {
        // path,name,regexp
        Object.assign(this, option)
        this.handle = fn
    }
}
class Router {
    constructor() {
        this.stack = []
    }

    use(path, fn) {
        const layer = new Layer({
            path,
            use: true,
            regexp: regExpCompile(path, []),
        }, fn)
        layer.route = null
        this.stack.push(layer)
    }

    route(path, fn, methods = []) {
        const route = new Route({
            path
        })
        methods.forEach(item => {
            route.addLayer(item, fn)
        })
        const layer = new Layer({
            path,
            regexp: regExpCompile(path, []),
        }, route.dispatch.bind(route))
        layer.route = route
        this.stack.push(layer)
    }

    handle(req, res, callback) {
        const {url} = req
        const {stack} = this
        let idx = 0

        next()

        function next() {
            let match = false
            let route = null
            let layer = null
            while (!match && idx < stack.length) {
                layer = stack[idx++]
                match = layer.regexp.exec(url)
                if (layer.use) match = true
                route = layer.route
                if (!match) continue
                if (!route) continue
            }
            if (!match) {
                callback && callback()
                return
            }
            layer.handle(req, res, next)
        }
    }

}
const app = {
    use: function (fn) {
        let router = this._router
        if (!router) {
            router = new Router()
            this._router = router
        }
        let path = '/'
        if (typeof fn !== 'function') {
            path = fn
            fn = arguments[1]
        }
        router.use(path, fn)

    },
    get: function (fn) {
        let router = this._router
        if (!router) {
            router = new Router()
            this._router = router
        }
        let path = '/'
        if (typeof fn !== 'function') {
            path = fn
            fn = arguments[1]
        }
        router.route(path, fn, ['get'])
    },
    post: function (fn) {
        let router = this._router
        if (!router) {
            router = new Router()
            this._router = router
        }
        let path = '/'
        if (typeof fn !== 'function') {
            path = fn
            fn = arguments[1]
        }
        router.route(path, fn, ['post'])
    },
    all: function () {

    },
    listen: function () {
        const _this = this

        const server = http.createServer(function (req, res) {
            _this._router.handle(req, res)
        })
        server.listen.apply(server, arguments)
    }
}
app.use((req, res, next) => {
    req.test = 'test1'
    next()
})
app.use((req, res, next) => {
    req.test2 = 'test2'
    next()
})
app.get('/', (req, res) => {
    const tst = req.test
    const tst2 = req.test2
    res.end('/' + tst + tst2)
})
app.get('/get', (req, res) => {
    const tst = req.test
    const tst2 = req.test2
    res.end('get' + tst + tst2)
})
app.get('/test', (req, res) => {
    const tst = req.test
    const tst2 = req.test2
    res.end('test' + tst + tst2)
})
app.listen(3300)

  

 

  代码仅供研究!

 

 博客园小结巴巴: https://www.cnblogs.com/jiebba

posted @ 2020-04-26 15:30  小结巴巴吧  阅读(316)  评论(0编辑  收藏  举报