上一篇理解Express的使用之后, 再总结一篇Express中间件的简单实现原理。

我们知道Express中间件就是一个个的函数, 那么怎么让这些函数有序的执行呢? 那就需要我们调用 next 函数。其实 next函数调用的就是下一个中间件函数。

以下代码实现了简单的 app.use 注册中间件, 以及 getpost方式的中间件。其他请求方式的中间件实现同理

核心代码:

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中间件简单的实现原理的更多相关文章

  1. Express中间件的原理及实现

    在Node开发中免不了要使用框架,比如express.koa.koa2拿使用的最多的express来举例子开发中肯定会用到很多类似于下面的这种代码 var express = require('exp ...

  2. Express中间件原理详解

    前言 Express和Koa是目前最主流的基于node的web开发框架,他们的开发者是同一班人马.貌似现在Koa更加流行,但是仍然有大量的项目在使用Express,所以我想通过这篇文章说说Expres ...

  3. express中间件原理 && 实现

    一.什么是express中间件? 什么是express中间件呢? 我们肯定都听说过这个词,并且,如果你用过express,那么你就一定用过express中间件,如下: var express = re ...

  4. express 中间件的简单应用与实现

    express 中间件的简单应用与实现 看了慕课网双越老师的课之后结合自己的理解做了一些简单的总结,如有不恰当之处,欢迎指正. 提到 express 就不得不提到中间件,接下来就简单的介绍一下 exp ...

  5. 1.express中间件的简介

    express中间件的意思 1, 中间件是一个模块.在js中,模块意味着函数,所以中间件是一个函数.那么这个函数长什么样子? 这还要从中间件的功能说起,它拦截http 服务器提供的请求和响应对象,执行 ...

  6. vue+webpack+express中间件接口使用

    环境:vue 2.9.3; webpack 目的:接口的调用 跨域方式: 1.express中间的使用 2.nginx代理 3.谷歌浏览器跨域设置 -------------------------- ...

  7. redux中间件和redux-thunk实现原理

    redux-thunk这个中间件可以使我们把这样的异步请求或者说复杂的逻辑可以放到action里面去处理,redux-thunk使redux的一个中间件,为什么叫做中间件 我们说中间件,那么肯定是谁和 ...

  8. 【nodejs原理&源码赏析(2)】KOA中间件的基本运作原理

    [摘要] KOA中间件的基本运作原理 示例代码托管在:http://www.github.com/dashnowords/blogs 在中间件系统的实现上,KOA中间件通过async/await来在不 ...

  9. Node.js连接Mysql,并把连接集成进Express中间件中

    引言 在node.js连接mysql的过程,我们通常有两种连接方法,普通连接和连接池. 这两种方法较为常见,当我们使用express框架时还会选择使用中间express-myconnection,可以 ...

随机推荐

  1. POJ1009 Edge Detection

    题目来源:http://poj.org/problem?id=1009 题目大意: 某图像公司用run length encoding(RLE)的方式记录和存储了大量的图像.程序的目标是读入压缩后的图 ...

  2. centos7网卡名称修改以及配置

    1.vi /etc/sysconfig/network-scripts/ifcfg-enoxxxxxx 为ifcfg-eth0并 将里面的NAME项修改为eth0 2.禁用该可预测命名规则.在启动时传 ...

  3. ACM-ICPC 2018 南京赛区网络预赛 J sum (找一个数拆成两个无平方因子的组合数)

    题目大意:就是找一个数拆成两个无平方因子的组合数,然后求个前缀和  ; 分析:运用筛法的思想 ,  因为有序对是由两个合法的数字组成的,所以只要保证第一个数合法,第二个数也合法就行,找出合法的第二个数 ...

  4. 73th LeetCode Weekly Contest Rotated Digits

    X is a good number if after rotating each digit individually by 180 degrees, we get a valid number t ...

  5. 原svn账户清除,及使用新用户名密码操作方法

    原svn账户清除,及使用新用户名密码操作方法 第一步:先清除原svn账户信息,如图示,电脑桌面右击“ToroiseSVN--Settings”. 在Settings中,选择Saved Data中的Cl ...

  6. 09.Spring Bean 注册 - BeanDefinitionRegistry

    基本概念 BeanDefinitionRegistry ,该类的作用主要是向注册表中注册 BeanDefinition 实例,完成 注册的过程. 它的接口定义如下: public interface ...

  7. 【Unity3D】简要分析unity3d中剪不断理还乱的yield

    在学习unity3d的时候很容易看到下面这个例子: void Start () { StartCoroutine(Destroy()); } IEnumerator Destroy(){ yield ...

  8. android 开发-ListView列表显示控件的实现

    列表的显示需要三个元素: 1.ListVeiw 用来展示列表的View. 2.适配器 用来把数据映射到ListView上的中介. 3.数据    具体的将被映射的字符串,图片,或者基本组件. 根据列表 ...

  9. SpringBoot | 第十三章:测试相关(单元测试、性能测试)

    前言 前面写了这么多章节,都是通过浏览器访问的形式,进行接口方法访问进而验证方法的正确与否.显然在服务或者接口比较少时,这么做没有啥问题,但一旦一个项目稍微复杂或者接口方法比较多时,这么验证就有点不符 ...

  10. elasticsearch报错:None of the configured nodes are available: []

    问题:在内网测试的时候可以正常访问,但是部署到外网上客户端连接elasticsearch报错:None of the configured nodes are available: [] 原因:默认情 ...