Express框架Router Route Layer对象使用示例详解

目录
  • 引言
  • Layer
  • Route
  • Router
  • 方法统计
  • 两个 stack
    • 取出 stack 中 layer
    • 从 Router 到 layer 的路径
    • Router.route 方法中的 dispatch
  • next 函数
  • 小结

引言

这使用倒叙的方式: 将 Layer 放在最前面讲解,然后是 Route 路由项目,最后是 Router 路由器。

Layer

Layer 是什么? Express 中最小的存储单元,存储的重要内容包括 handle 也就是 fn、path 等路径。fn 就是中间件处理函数。重要的是 route 中能匹配:

module.exports = Layer;
function Layer(path, options, fn) {
  if (!(this instanceof Layer)) {
    return new Layer(path, options, fn);
  }
  var opts = options || {};
  this.handle = fn;
  this.name = fn.name || '<anonymous>';
  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
}
Layer.prototype.handle_error = function handle_error(error, req, res, next) {}
Layer.prototype.handle_request = function handle(req, res, next) {}
Layer.prototype.match = function match(path) {} // 返回 boolean

看看哪些的内容实例化了 Layer 的构造函数。Layer 的最主要的作用就是,被路由匹配到,然后取出 handle 函数最后调用,消费 handle 函数。

  • Route

一个 Route 的栈 stack 中,可以存放多个 Layer。

Route.prototype.all = function all() {
    /**/
    var layer = Layer('/', {}, handle);
    /**/
}
Route.prototype[method] = function(){
   /**/
   var layer = Layer('/', {}, handle);
   /**/
}
  • Router 中
proto.route = function route(path) {
  // ***
  var layer = new Layer(path, {
    sensitive: this.caseSensitive,
    strict: this.strict,
    end: true
  }, route.dispatch.bind(route));
 // ***
 this.stack.push(layer);
};
proto.use = function use(fn) {
     var layer = new Layer(path, {
      sensitive: this.caseSensitive,
      strict: false,
      end: false
    }, fn);
    this.stack.push(layer);
}

在 Router 中的 route 和 use 函数,使用 Layer 构造函数实例化 layer, 然后将 layer 压到 stack 中保存卡里,方便以后匹配。

  • layer 的匹配方法
function matchLayer(layer, path) {
  try {
    return layer.match(path);
  } catch (err) {
    return err;
  }
}

从上面的代码中知道,layer 对象的 match 方法,根据路径进行匹配, match 返回 boolean. 在匹配的时候主要处理了两个属性:

this.params = undefined;
this.path = undefined;

接下来看 matchLayer 函数, matchLayer 调用在 Router.handle 函数的 next 函数中。

Route

module.exports = Route;
function Route(path) {
  this.path = path;
  this.stack = [];
  this.methods = {};
}
Route.prototype._handles_method = function _handles_method(method) {/*...*/}
Route.prototype._options = function _options() {/*...*/}
Route.prototype.dispatch = function dispatch(req, res, done) {/*...*/}
Route.prototype.all = function all() {/*...*/}
// 扩展 methods 包中的方法

Router

Router 就是 proto

var proto = module.exports = function(options) {/*...*/}
proto.param = function param(name, fn) {/*...*/}
proto.handle = function handle(req, res, out) {/*...*/}
proto.process_params = function process_params(layer, called, req, res, done) {/*...*/}
proto.use = function use(fn) {/*...*/}
proto.route = function route(path) {/*...*/}
// 扩展 methods + all 上所有的方法

注意: Router.handle 函数.

var stack = self.stack;
while (match !== true && idx < stack.length) {/*...*/}

在 while 循环中,使用 idx 中取出 layer 和 path然后交给 matchLayer 函数, 得到匹配结果。如果调用的内容正常:

layer.handle_request(req, res, next) // 最终会得到中间件的处理函数

接下来盘点, Router/Route/Layer 的常用方法

方法统计

  • Router
Router 方法 说明
Router param 参数
Router handle 处理函数
Router process_params 处理参数
Router use 中间件
Router route 路由
Router [methods]/all 各种方法
  • Route
Route 方法 说明
Route _handles_method 私有处理函数
Route _options 私有选项
Route dispatch 派发请求和响应
Route all 各种方法
Route [methods] 各种方法
  • Layer
Layer 方法 说明
Layer handle_error 处理错误
Layer handle_request 处理请求
Layer match 根据路径匹配路由并返回 boolean

看 Router 和 Route 有相同的方法: all/[methods]。使用 Router.route 的方法通过 path 方法关联。同时 咋 Router.route 中实例化 Layer ,然后将 layer 保存在 Router 的 stack 中。

两个 stack

从上面的分析中,知道了 Router 中有 stack,Route 中也有 stack, 在 stack 中添加内容(也就是 Layer)一般都是与路由和中间件相关。

  • Router 的 use 方法中,包含了实例化 Layer, 并存储在 Router 级别的 stack 中。
  • Router 的 route 中,实例化了 Layer, 并存储在 Router 级别的 stack 中。
  • Router 的 [methods]/all 方法中,调用了 route 方法,自然也存储了 stack

取出 stack 中 layer

取出 Layer 发生在 Route 的 dispatch 函数 的 next 函数中,此时需要调用 layer 中匹配到的参数。

从 Router 到 layer 的路径

  • Router 是被 express 单独的输出出去的。
  • Router 实例化之后,可以调用 use/[methods] 实例化 Layer 并保存 stack 中,当然也可调用 Router.route 方法。

Router.route 方法中的 dispatch

var layer = new Layer(path, {
    sensitive: this.caseSensitive,
    strict: this.strict,
    end: true
}, route.dispatch.bind(route));

route.dispatch 在此处 bind 绑定,此时作为 Layer 构造函数的第三个参数,保存为 handle, 最后会被拿出调用。此时就进入了 next 函数调用阶段。

next 函数

next 函数是 Express 中间件的基础,dispatch 函数从 当前的 stack 中拿出 layer 的实际情况调用 layer 不同的方法。

if (layer.method && layer.method !== method) {
  next(err)
}

当 layer 中的方法或者等于但当前的方法时,调用自己,此时 next 函数发生了递归。否则进入 handle 相关方法处理请求和处理错阶段,此时 next 方法发生了递归调用。

小结

  • Router -> Route -> Layer
  • Router -> use -> Layer
  • Router 和 Route 都有自己 stack 存储 layer
  • next 函数在 Route 的 dispatch 被执行,并在 layer 相关属性中发生 next 函数的递归,实现了 Express 的中间件。

以上就是Express框架Router Route Layer对象使用示例详解的详细内容,更多关于Express使用Router Route Layer的资料请关注我们其它相关文章!

(0)

相关推荐

  • Express框架req res对象使用详解

    目录 正文 IncomingMessage ServerResponse 请求对象 req 响应对象 设置状态码 如何来快速测试这些属性和方法呢? 下面给出一些示例代码 目录结构 安装依赖 小结 正文 Express 请求 req 和响应 res 对象定义: var req = Object.create(http.IncomingMessage.prototype) var res = Object.create(http.ServerResponse.prototype) 下面是属性继承关系

  • Express代理转发服务器实现

    目录 express的代理转发 项目结构 转发 转发记录 前端页面 express的代理转发 其实我的内心关于这个Express,我的内心是拒绝的,不是说,我对这个框架有什么看法,而是因为这个大作业的问题.是的我还是一个大三老菜鸡,苦练 Java 全干开发,Python 人工智能 整整 一坤年.期间拿了几个奖,水了篇论文 而已. 那么这篇文章主要做的,其实很简单就是,做个代理转发.前端请求,先到express服务器,然后转发到flask服务器,为什么非要转发呢,原因很简单,web作业非要用nod

  • Express框架两个内置中间件方法详解

    目录 什么是中间件 两个内置的中间件 init 方法 query 中间件 被使用 小结 什么是中间件 中间件,就是具有串联执行能力的函数,Express中两种层面的中间件.app 层面的中间件, router 层面的中甲件.在 express 中, 一般通过 use 方法和路由的方法添加中间件. 两个内置的中间件 init 中间件方法 query 中间件方法 init 方法 exports.init = function(app){ return function expressInit(req

  • react express实现webssh demo解析

    目录 正文 实现 WebSSH 的基本思路 实现 Demo 的代码 服务器端代码 前端代码 在 React 应用中使用 WebSSH 组件 效果 总结 正文 下面是一个简单的 WebSSH Demo,实现了通过浏览器连接 SSH 服务器并进行交互的功能. 实现 WebSSH 的基本思路 WebSSH 可以分成以下几个模块: 前端界面:使用 xterm.js 实现一个基于浏览器的终端界面. WebSocket 连接:使用 WebSocket 连接连接 WebSSH 服务器后端. SSH 连接:使用

  • Express框架中_router 对象数据结构使用详解

    目录 _router 对象介绍 使用调试直观的获取 _router 对象 一个简单的可以运行的 demo 使用 vscode 初始化一个调试文件 在合适的地点打一个断点 启动服务 观察全部属性并找到 _router 对象以及属性 找出 stack.layer 的排列顺序 分析 _router 的嵌套对象 _router 对象的相关源码 _router 的数据结构分析 小结 _router 对象介绍 _router 对象是一个私有的属性,但是它保存了重要的内容.其中就包括所有的合理的 Layer

  • Java框架设计灵魂之反射的示例详解

    目录 获取Class对象的方式 Class对象功能 获取成员变量们 获取构造方法们 获取成员方法们 获取全类名 Field:成员变量 Constructor:构造方法 Method:方法对象 案例 框架:半成品软件.可以在框架的基础上进行软件开发,简化编码. 反射就是把Java类中的各个成员映射成一个个的Java对象. 即在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能调用它的任意一个方法和属性. 这种动态获取信息及动态调用对象方法的功能叫Java的反射机

  • JavaIO字符操作和对象操作示例详解

    目录 字符操作 编码与解码 String 的编码方式 Reader 与 Writer 实现逐行输出文本文件的内容 对象操作 序列化 Serializable transient 字符操作 编码与解码 编码就是把字符转换为字节,而解码是把字节重新组合成字符. 如果编码和解码过程使用不同的编码方式那么就出现了乱码. GBK 编码中,中文字符占 2 个字节,英文字符占 1 个字节: UTF-8 编码中,中文字符占 3 个字节,英文字符占 1 个字节: UTF-16be 编码中,中文字符和英文字符都占

  • c#对象反序列化与对象序列化示例详解

    1.对象序列化的介绍 (1).NET支持对象序列化的几种方式二进制序列化:对象序列化之后是二进制形式的,通过BinaryFormatter类来实现的,这个类位于System.Runtime.Serialization.Formatters.Binary命名空间下.SOAP序列化:对象序列化之后的结果符合SOAP协议,也就是可以通过SOAP 协议传输,通过System.Runtime.Serialization.Formatters.Soap命名空间下的SoapFormatter类来实现的.XML

  • golang遍历时修改被遍历对象的示例详解

    前言 很多时候需要将遍历对象中去掉某些元素,或者往遍历对象中添加元素,这时候就需要小心操作了. 对于go语言中的一些注意事项我做了总结和示例,留下点笔记. 遍历切片 1.遍历切片时去掉元素,错误示例: func main() { arr := []int{1, 2, 3, 4} for i := range arr { if arr[i] == 3 { arr = append(arr[:i], arr[i+1:]...) } } fmt.Println(arr) } 最终报错panic: ru

  • C++预定义的流对象基本示例详解

    目录 C++预定义的流对象 示例说明 总结: C++预定义的流对象 C++预定义的流对象是可用于输入和输出的数据流向对象.它们是在C++语言中内置的,可以使用标准库的iostream头文件来调用这些流对象. 在这篇文章中,我们将介绍C++预定义的流对象,并提供一些示例说明. 示例说明 cin: cin是标准输入流对象,用于从控制台读取输入. 示例: int num; cout << "Enter a number: "; cin >> num; cout <

  • spring MVC中传递对象参数示例详解

    前言 初学java,由于项目紧急,来不及仔细的研究,在传递参数时就老老实实的一个一个的采用@RequestParam注解方式传递,最近认真看了一下,发现java也具有类似Asp.net Mvc传递对象做参数的方式,即采用@ModelAttribute注解的方式,接收方式如下: @RequestMapping("hello") public String Hello(@ModelAttribute("user") User user) { System.out.pri

  • Pandas之MultiIndex对象的示例详解

    约定 import pandas as pd from pandas import DataFrame import numpy as np MultiIndex MultiIndex表示多级索引,它是从Index继承过来的,其中多级标签用元组对象来表示. 一.创建MultiIndex对象 创建方式一:元组列表 m_index1=pd.Index([("A","x1"),("A","x2"),("B",&q

  • SSM框架整合JSP中集成easyui前端ui项目开发示例详解

    目录 前言 EasyUI下载与配置 页面美化 运行结果 总结与问题 前言 前端的UI框架很多,如bootsrap.layui.easyui等,这些框架提供了大量控件供开发人员使用,我们无需花费太大的精力,使得我们的页面具有专业标准,使用起来也很简单.所有的前端框架使用方式基本上大同小异,以下使用easyui作为UI框架做一演示,个人认为easyui提供的控件比较好看. EasyUI下载与配置 使用EasyUI,必须下载其js包,下载官网地址:https://www.jeasyui.cn/ 下载j

  • Python开发自定义Web框架的示例详解

    目录 开发自定义Web框架 1.开发Web服务器主体程序 2.开发Web框架主体程序 3.使用模板来展示响应内容 4.开发框架的路由列表功能 5.采用装饰器的方式添加路由 6.电影列表页面的开发案例 开发自定义Web框架 接收web服务器的动态资源请求,给web服务器提供处理动态资源请求的服务.根据请求资源路径的后缀名进行判断: 如果请求资源路径的后缀名是.html则是动态资源请求, 让web框架程序进行处理. 否则是静态资源请求,让web服务器程序进行处理. 1.开发Web服务器主体程序 1.

随机推荐