美文网首页
Koa源码简单实现

Koa源码简单实现

作者: Sommouns | 来源:发表于2020-01-29 12:45 被阅读0次

github地址https://github.com/sommouns/my_koa

const http = require('http')

const context = require('./context')
const request = require('./request')
const response = require('./response')

class SKoa {
    constructor() {
        this.middlewares = []
    }

    // 核心目的就是开个http服务
    listen (...args) {
        const server = http.createServer(async (req, res) => {
            // 创建上下文
            let ctx = this.createContext(req, res)

            // 合并中间件
            const fn = this.compose(this.middlewares)

            // 执行中间件的聚合物
            await fn(ctx)
            res.end(ctx.body)
        })
        server.listen(...args)
    }

    use (middleware) {
        this.middlewares.push(middleware)
    }

    createContext (req, res) {
        // 主要就是对request和response做一层封装,然后全部存到ctx上
        const ctx = Object.create(context)
        ctx.request = Object.create(request)
        ctx.response = Object.create(response)

        ctx.req = ctx.request.req = req
        ctx.res = ctx.response.res = res
        return ctx
    }

    compose (middlewares) {
        return function (ctx) {
            return dispatch(0)

            function dispatch (i) {
                let fn = middlewares[i]
                if (!fn) {
                    return Promise.resolve()
                }
                return Promise.resolve(
                    fn(ctx, function next () {
                        return dispatch(i + 1)
                    })
                )
            }
        }
    }
}

module.exports = SKoa
// context.js

module.exports = {
    get url () {
        return this.request.url
    },
    get body () {
        return this.response.body
    },
    set body (val) {
        this.response.body = val
    },
    get method () {
        return this.request.method
    }
}
// request.js

module.exports = {
    get url () {
        return this.req.url
    },
    get method () {
        return this.req.method.toLowerCase()
    }
}
// response.js

module.exports = {
    get body () {
        return this._body
    },
    set body (val) {
        this._body = val
    }
}

然后附上一些常用的中间件的实现


Logger

module.exports = async (ctx, next) => {
    const start = Date.now()
    await next()
    const end = Date.now()
    console.log('request ' + ctx.url + ', using ' + parseInt(end - start) + 'ms')
}

Router

Router主要的思路就是返回一个routes方法,它可以返回一个中间件。这个中间件用途也很简单,就是去匹配路由,当method和url匹配上之后,去调用后面再传入的中间接就可以了,要注意异步的问题!

class Router {
    constructor() {
        this.stack = []
    }

    register (path, method, middleware) {
        let route = { path, method, middleware }
        this.stack.push(route)
    }

    get (path, middleware) {
        this.register(path, 'get', middleware)
    }

    post (path, middleware) {
        this.register(path, 'post', middleware)
    }

    routes () {
        let stock = this.stack
        return async (ctx, next) => {
            let currentPath = ctx.url
            let route

            for (let i = 0; i < stock.length; i++) {
                let item = stock[i]
                if (currentPath === item.path && item.method.indexOf(ctx.method) >= 0) {
                    route = item.middleware
                    break
                }
            }

            if (typeof route === 'function') {
                await route(ctx, next)
                return
            }

            await next()
        }
    }
}

module.exports = Router

Static

思路很简单,就是去读路径,然后文件夹和文件分开处理(这里简单起见,只是颜色不同),文件夹就可以直接html拼接输出,文件就直接去读即可

const fs = require('fs')
const path = require('path')

module.exports = (dirPath = './public') => {
    return async (ctx, next) => {
        if (ctx.url.startsWith('/public')) {
            const url = path.resolve(__dirname, dirPath)
            const fileBaseName = path.basename(url)
            const filePath = url + ctx.url.replace('/public', '')
            console.log(filePath)

            try {
                const stats = fs.statSync(filePath)
                // const
                if (stats.isDirectory()) {
                    const dir = fs.readdirSync(filePath)
                    const ret = ['<div style="padding-left:20px">']
                    dir.forEach(filename => {
                        if (filename.indexOf('.') > -1) {
                            ret.push(
                                `<p><a style="color: black" href="${ctx.url}/${filename}">${filename}</a></p>`
                            )
                        } else {
                            ret.push(
                                `<p><a href="${ctx.url}/${filename}">${filename}</a></p>`
                            )
                        }
                    })
                    ret.push('</div>')
                    ctx.body = ret.join('')
                } else {
                    const content = fs.readFileSync(filePath)
                    ctx.body = content
                }
            } catch (e) {
                ctx.body = "404 not found"
            }
        } else {
            await next()
        }
    }
}

相关文章

  • Koa源码简单实现

    github地址https://github.com/sommouns/my_koa 然后附上一些常用的中间件的实...

  • 《Koa诞生记》——如何写好README

    回顾前三章内容,讨论了koa的核心模块 koa-compose的实现,自己实现一个简单的koa,以及koa实现 s...

  • 【koa2】koa-static-router 中间件搭建静态资

    koa中间件 koa-static-router中间件搭建静态资源服务器, 实现多个&&多层路由加载静态资源 源码...

  • Koa源码阅读

    Koa源码 继着上文的Co源码以及与Koa的深入理解,开始学习下Koa是怎么写的。我看的版本是1.1.2的。 从p...

  • 十分钟带你看完 KOA 源码

    前段时间看了 koa 源码,得益于 koa 良好抽象,不仅提供了简洁的 api ,同时也使得源码相当的简洁和优雅。...

  • Koa2源码阅读: 中间件机制

    中间件机制(洋葱模型):它实现中间件级联调用是借助 koa-compose这个库来实现的。源码只有一个函数。 我...

  • 4.2 koa源码浅析

    本节将带着大家简单看一下koa2.x最新版本的源码。 源码结构 在上一章我们已经分享了查看依赖库源码的方法,本节我...

  • 基于koa实现mvc

    之前使用了基于koa2的MVC结构的 egg 框架,大概理解是egg的使用规范。所以这里我们也简单的实现基于koa...

  • Koa 洋葱模型简单实现

    直接上代码 测试 运行,在浏览器中访问http://localhost:19191/[http://localho...

  • koa实现简单图片上传

    搭建koa基础结构 新建一个文件夹 执行npm init -y 安装koa koa-router 新建app.js...

网友评论

      本文标题:Koa源码简单实现

      本文链接:https://www.haomeiwen.com/subject/nemvthtx.html