这是渐进式Express源码学习 | 小白也能懂源码系列文章的第四篇。
请结合该节代码阅读Lesson4-如虎添翼
目录
- 渐进式Express源码学习1.万物归宗
- 渐进式Express源码学习2.道士下山
- 渐进式Express源码学习3.初露锋芒
- 渐进式Express源码学习4.如虎添翼
- 渐进式Express源码学习5.全副武装
- 渐进式Express源码学习6.独孤求败
目标特性和目标用法
这篇文章里,我们在第三篇文章的基础上,实现一个稍微加强版的Express,功能包括
- 引入path,即app.get(‘user’, handler)
- 不同path由不同的函数来处理
这篇文章要实现的express的期望用法如下
const express = require('../index.js')
const app = express()
app.get('/foo', function (req, res, next) {
res.end('Welcome to GET /foo')
})
app.get('/bar', function (req, res, next) {
res.end('Welcome to GET /bar')
})
app.post('/foo', function (req, res, next) {
res.end('Welcome to POST /foo')
})
app.listen(3000)
源码及讲解
** Path的验证,核心是由layer.match进行的路由判断** 为了实现这个功能,我们共需要作出4个改进
- lib/layer.js
- 构造函数传入path
- 增加了match函数
- lib/route.js
- 构造函数传入path
- 新增lib/route/index.js文件
- express.js
- 增加.lazyrouter函数
首先看下目前的项目结构
从图中我们可以看出,我们把layer,route都放到了lib/route文件夹里,里面的index.js就是我们刚才说的新增的lib/route/index.js文件
我们先来看layer文件的变化
主要的变化在两点,第一点是构造函数
注意,构造函数传入了一个path,然后还调用了pathRegexp函数。而这个pathRegexp函数其实是从path-to-regexp模块来的,他的作用是解析路径做匹配,可以直接看一个例子
const pathRegexp = require('path-to-regexp')
const keys = []
const result = pathRegexp('/foo/:bar', keys)
运行之后,keys和result分别是
result = /^\/foo\/([^\/]+?)\/?$/i
keys = [{name: 'bar', prefix: '/'}]
也就是说,result是一个正则表达式,而keys保存了path中的参数
我们再看layer的第二个变化,就是新增了match函数,如下
最后两句是关键,调用正则表达式匹配目标path是否和layer的path相符合,并返回布尔值 到这里,我们就清晰了,path是在layer的match函数里匹配的。那match函数是在哪里调用的呢?继续往下看
我们再看lib/route/index.js文件
因为route.js几乎没什么变化,所以我们直接看lib/route/index.js文件 这个文件里,定义的是Router对象 我们的设计思路是:
- app.get app.post等这类app.verb,最后本质上调用的是Router.verb
- 当请求来临时,最后调用的是Router.handle 先看Router.verb
也就是说,当我们调用app.get(path, fn)的时候,Router创建了一个route进行了处理,同时把这个route的dispatch挂载到一个新的layer上,然后把这个layer推送到自己的stack中,大概是这样的结构
左边的三个layer的handle都是route.dispatch,右边的3个layer的handler才是我们传入app.get的函数
再看handle函数,当有请求时,这个函数会被调用 整体的流程是遍历stack中的layer,然后调用这个layer的handle_request,实际上是调用了layer对应的route的dispatch函数。他是通过一个next递归实现的。
看36行的matchLayer函数
到这里我们就明白了,layer的match函数是在这个地方被调用的 注意
本文总结及预告
本文实现了一个加强的Express,可以传入path,本质上是通过path-to-regexp来实现的路径的判断