Express中间件简单的实现原理
上一篇理解Express的使用之后, 再总结一篇Express中间件的简单实现原理。
我们知道Express中间件就是一个个的函数, 那么怎么让这些函数有序的执行呢? 那就需要我们调用 next 函数。其实 next函数调用的就是下一个中间件函数。
以下代码实现了简单的 app.use 注册中间件, 以及 get、post方式的中间件。其他请求方式的中间件实现同理
核心代码:
const next = () => {
    const stack = stacks.shift()
    if(stack) {
        stack(req, res, next)
    }
}
next()
stacks就是一个数组队列, 存放所有符合规则的中间件函数。遵循先进先出的原则。也就是最先注册的中间件函数最先执行。
实现代码
const http = require('http')
const slice = Array.prototype.slice
 class Express {
     constructor() {
        this.router = {
            all: [], // 匹配所有额中间件函数
            get: [],
            post: []
        }
     }
     /**
      * 这里整合中间件
      * @param {string} path
      * @returns {object}
      */
     middlewareHandler(path) {
        const info = {}
        if (typeof path === 'string') {
            info.path = path
            info.stack = slice.call(arguments, 1)  // 中间件数组
        } else {
            info.path = '/'
            info.stack = slice.call(arguments, 0)
        }
        return info
     }
     use() {
        const allStack = this.middlewareHandler(...arguments)
        this.router.all.push(allStack)
     }
     get() {
        const getStack = this.middlewareHandler(...arguments)
        this.router.get.push(getStack)
     }
     post() {
        const postStack = this.middlewareHandler(...arguments)
        this.router.post.push(postStack)
     }
      /**
       *
       * @param {string} method
       * @param {string} url
       * @returns {Array}
       */
     accordStack(method, url) {
        let stacks = []
        stacks = stacks.concat(this.router.all)
        stacks = stacks.concat(this.router[method])
        return stacks
        .filter(stack => {
            return url.indexOf(stack.path) !== -1
        }).map(item => item.stack[0])
     }
     handler(req, res, stacks) {
         // 函数表达式
        const next = () => {
            const stack = stacks.shift()
            if(stack) {
                stack(req, res, next)
            }
        }
        next()
     }
     callback() {
        return (req, res) => {
            res.json = data => {
                res.setHeader('Content-Type', 'application/json')
                res.end(JSON.stringify(data))
            }
            // 拿到请求的方法和url, 对中间件函数进行筛选
            const {method, url} = req
            const stacks = this.accordStack(method.toLowerCase(), url)
            this.handler(req, res, stacks)
        }
     }
     listen(...args) {
         const server = http.createServer(this.callback())
         server.listen(...args)
     }
 }
 // 工厂模式, 导出一个实例对象
module.exports = () => {
    return new Express()
}												
											Express中间件简单的实现原理的更多相关文章
- Express中间件的原理及实现
		
在Node开发中免不了要使用框架,比如express.koa.koa2拿使用的最多的express来举例子开发中肯定会用到很多类似于下面的这种代码 var express = require('exp ...
 - Express中间件原理详解
		
前言 Express和Koa是目前最主流的基于node的web开发框架,他们的开发者是同一班人马.貌似现在Koa更加流行,但是仍然有大量的项目在使用Express,所以我想通过这篇文章说说Expres ...
 - express中间件原理 && 实现
		
一.什么是express中间件? 什么是express中间件呢? 我们肯定都听说过这个词,并且,如果你用过express,那么你就一定用过express中间件,如下: var express = re ...
 - express 中间件的简单应用与实现
		
express 中间件的简单应用与实现 看了慕课网双越老师的课之后结合自己的理解做了一些简单的总结,如有不恰当之处,欢迎指正. 提到 express 就不得不提到中间件,接下来就简单的介绍一下 exp ...
 - 1.express中间件的简介
		
express中间件的意思 1, 中间件是一个模块.在js中,模块意味着函数,所以中间件是一个函数.那么这个函数长什么样子? 这还要从中间件的功能说起,它拦截http 服务器提供的请求和响应对象,执行 ...
 - vue+webpack+express中间件接口使用
		
环境:vue 2.9.3; webpack 目的:接口的调用 跨域方式: 1.express中间的使用 2.nginx代理 3.谷歌浏览器跨域设置 -------------------------- ...
 - redux中间件和redux-thunk实现原理
		
redux-thunk这个中间件可以使我们把这样的异步请求或者说复杂的逻辑可以放到action里面去处理,redux-thunk使redux的一个中间件,为什么叫做中间件 我们说中间件,那么肯定是谁和 ...
 - 【nodejs原理&源码赏析(2)】KOA中间件的基本运作原理
		
[摘要] KOA中间件的基本运作原理 示例代码托管在:http://www.github.com/dashnowords/blogs 在中间件系统的实现上,KOA中间件通过async/await来在不 ...
 - Node.js连接Mysql,并把连接集成进Express中间件中
		
引言 在node.js连接mysql的过程,我们通常有两种连接方法,普通连接和连接池. 这两种方法较为常见,当我们使用express框架时还会选择使用中间express-myconnection,可以 ...
 
随机推荐
- element-ui国际化探索(大型项目适用)
			
配置好了,自己感觉是比较简单的,就是有一点点繁琐,加油吧. 由于保密,无法拿出项目,故写了一个小demo,记录一下,适用于大型项目: 项目中需要自定义切换中/英文(国际化),基于vue.js,结合vu ...
 - ubuntu设置nginx为系统服务
			
ubuntu设置nginx为系统服务,如果没有设置为系统服务,无法执行 sudo service nginx startsudo service nginx stop 设置为系统服务命令 sudo u ...
 - 洛谷P5279 [ZJOI2019]麻将
			
https://www.luogu.org/problemnew/show/P5279 以下为个人笔记,建议别看: 首先考虑如何判一个牌型是否含有胡的子集.先将牌型表示为一个数组num,其中num[i ...
 - jvm 锁Lock
			
自旋锁 线程想要获得一个对象的锁,如果没有得到,会继承占用CPU尝试获取锁, 线程不进入阻塞状态,仍然在Running 锁消除 public void lockTest() { String aa = ...
 - python模块之time方法详细介绍
			
>>> import time >>> dir(time) ['_STRUCT_TM_ITEMS', '__doc__', '__loader__', '__nam ...
 - mysql 主从复制以及binlog 测试
			
###mysql查看binlog日志内容 https://blog.csdn.net/nuli888/article/details/52106910 mysql的binlog日志位置可通过show ...
 - 关于vi 分屏的一些指令
			
分屏都是以ctrl + W(大写) 首先,ctrl+ W , v 为切屏 之后用 :e 打开其他文件 ctrl + W , c 为关闭当前分屏 ctrl + W , h 为切换到左侧分屏 ...
 - 牛客网Java刷题知识点之四种不同的方式创建线程
			
不多说,直接上干货! 有4种方式可以用来创建线程: 第一种:继承Thread类,重写run方法 第二种:实现Runnable接口,并实现该接口的run方法(一般我们在编程的时候推荐用这种) 第三种:实 ...
 - xcrun -sdk 选择
			
在将FFmpeg编译成IOS版的时候,接触到编译脚本的一段(删减了部分): for ARCH in $ARCHS do if [ "$ARCH" = "i386" ...
 - jQuery实现加载中效果,防止重复提交
			
//导出表格加载中的提示var dian=0;//控制'●'的个数var t=null;//停止时使用function id_loadspot(loadspotSpan,loadingDiv,expo ...