上一篇理解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. Jmeter_前端RSA加密下的登陆模拟_引用js文件实现(转)

    在一次项目实战中,前端登录使用了RSA加密,使用LoadRunner压测的第一步,就是模拟用户登录,可惜loadRunner11并不能录制前端的加密过程,并且安装的LR是基于C语言版,网络上关于RSA ...

  2. emmet缩写大全

    Syntax   Child: > nav>ul>li <nav> <ul> <li></li> </ul> </n ...

  3. jquery——幻灯片(只动一屏)

    制作天天生鲜的幻灯片部分 贴了全部代码: main.html: <!DOCTYPE html> <html lang="en"> <head> ...

  4. about 字节

    关于由于赋值导致字节的截断.字节扩展及数据类型的提升: 一.字节截断:int----->char 当一个字节(8位)放不下时,出现截断,直接取(最后一个字节)最后面面8位. 例如:1000000 ...

  5. pat1055. The World's Richest (25)

    1055. The World's Richest (25) 时间限制 400 ms 内存限制 128000 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue ...

  6. Srping MVC中Controller的void方法

    第一种 通过修改response来修改页面 /** * 方式一:通过声明HttpServletResponse类型的方法入参,来使用HttpServletResponse对象. * 注意:在Contr ...

  7. 使用WinSCP上传文件到linux系统

    1.安装WinSCP 2.新建脚本test.txt option confirm off open username:password@host put C:\test\a.zip /home/tes ...

  8. ElasticSearch入门-搜索(java api)

    ElasticSearch入门-搜索(java api) package com.qlyd.searchhelper; import java.util.Map; import net.sf.json ...

  9. php编码转换相关

    iconv (PHP 4 >= 4.0.5, PHP 5, PHP 7) iconv — 字符串按要求的字符编码来转换 string iconv ( string $in_charset , s ...

  10. Excel2Dataset

    //获取用户打开的Excel文档路径 private stringkkk() { OpenFileDialog selectFile = new OpenFileDialog(); selectFil ...