博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.6-浅析express源码之Router模块(2)-router.use
阅读量:5268 次
发布时间:2019-06-14

本文共 2971 字,大约阅读时间需要 9 分钟。

  这一节继续深入Router模块,首先从最常用的use开始。

 

router.use

  方法源码如下:

proto.use = function use(fn) {    var offset = 0;    var path = '/';    if (typeof fn !== 'function') {        var arg = fn;        while (Array.isArray(arg) && arg.length !== 0) arg = arg[0];        if (typeof arg !== 'function') {            offset = 1;            path = fn;        }    }    var callbacks = flatten(slice.call(arguments, offset));    if (callbacks.length === 0) throw new TypeError('Router.use() requires a middleware function')    for (var i = 0; i < callbacks.length; i++) {        var fn = callbacks[i];        if (typeof fn !== 'function') throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))        debug('use %o %s', path, fn.name || '
'); // 内部模块layer! var layer = new Layer(path, { sensitive: this.caseSensitive, strict: false, end: false }, fn); // 通过use方法生成的layer没有route值 layer.route = undefined; // 初始化时定义的数组 this.stack.push(layer); } return this;};

  前半部分十分熟悉,根本就是app.use的翻版。

  当然,最后遍历中间件函数处理的时候就不一样了,引入了新的本地模块Layer。

 

Layer

  不太理解这个层的意义,无论是app.use还是router.use,每一个中间件都会生成一个layer对象,然后push进router上的stack数组。

  那么多路径呢,是否会生成多个layer?答案是否。

  看一眼layer的构造函数:

function Layer(path, options, fn) {    if (!(this instanceof Layer)) {        return new Layer(path, options, fn);    }    debug('new %o', path)    var opts = options || {};    /**     * layer.handle => 中间件函数     * layer.name => 函数名     * layer.regexp => 路径的正则     */    this.handle = fn;    this.name = fn.name || '
'; this.params = undefined; this.path = undefined; this.regexp = pathRegexp(path, this.keys = [], opts); // 快速匹配标记 this.regexp.fast_star = path === '*' this.regexp.fast_slash = path === '/' && opts.end === false}

  其中比较关键一步是根据传进来的path生成一个正则,pathRegexp是一个工具模块,无论传进去的是字符串、数组、正则都能返回一个正则匹配需要的值。

  简略的看一下工具核心源码:

function pathtoRegexp(path, keys, options) {    // ...    // 字符串    path = ('^' + path + (strict ? '' : path[path.length - 1] === '/' ? '?' : '/?'));    // ...后面有很多replace    // 数组    if (Array.isArray(path)) {        path = path.map(function(value) {            return pathtoRegexp(value, keys, options).source;        });        // 使用|分割多个规则来进行多重匹配        return new RegExp('(?:' + path.join('|') + ')', flags);    }    // 正则 比较简单的    // var MATCHING_GROUP_REGEXP = /\((?!\?)/g;    if (path instanceof RegExp) {        // 匹配组        while (m = MATCHING_GROUP_REGEXP.exec(path.source)) {            keys.push({                name: name++,                optional: false,                offset: m.index            });        }        return path;    }}

  字符串模式非常复杂,因为允许类正则写法的字符串,解析会变得十分复杂,后面有很多很多的replace,这里给一个开头,比较简单过把瘾。

  最后返回一个匹配路径的正则表达式,然后在该对象上加两个标记,比如说如果一个Layer的正则对象有全局路由标记,则根本不用正则校验,直接可以调用中间件。

  返回Layer对象后,该对象会被push进router的stack数组。

  

  这节就简单过一下Router模块的use方法,下一节看看具体请求方法的源码流向。

转载于:https://www.cnblogs.com/QH-Jimmy/p/8868633.html

你可能感兴趣的文章
无法像唐骏一样地成功
查看>>
Spark一个简单案例
查看>>
linux red hat下安装tomcat的过程
查看>>
【BZOJ4173】数学 欧拉函数神题
查看>>
安装SpringExt以查看schema文件
查看>>
Redis入门必读,The Little Redis Book中文版
查看>>
【转】box盒模型
查看>>
洛谷3769[CH弱省胡策R2]TATT (KDTree)(四维LIS)
查看>>
POJ1050To the Max(求最大子矩阵)
查看>>
洛谷P1006 传纸条【dp】
查看>>
C/C++ 安全编码 —— 指针与内存
查看>>
【数学】十万个为什么(一) —— 为什么乘法会分为左乘和右乘,除法会分为左除和右除?...
查看>>
中英文对照 —— 缩略词
查看>>
分词器的使用
查看>>
DOMContentLoaded实现
查看>>
hybird app(混合式app开发)cordova ionic 创建相应平台的app
查看>>
js注册事件的on addEventListener attachEvent的区别和兼容性
查看>>
数据库中函数总结
查看>>
C#多线程--信号量(Semaphore)
查看>>
Linux之磁盘分区
查看>>