const express = require("express");
const app = express();
app.get("/test", (req, res, next) => {
console.log("会所技师到位*1");
// res.end("会所技师开始服务1");
next();
});
app.get("/test", (req, res, next) => {
console.log("会所技师到位*2");
res.end("会所技师开始服务2");
});
app.listen(8888, (err) => {
!err && console.log("会所里面有大保健吗?");
});
localhost:8888/test
时候,返回了:会所技师开始服务 2
,服务端打印了会所技师到位*1
会所技师到位*2
app.listen
会启动进程监听端口url
和method
会触发相应挂载在app
上对应的回调函数next
方法,会触发下一个express
默认引入调用后返回一个app
对象express
框架express
文件入口,这里使用class
来实现class express {
}
module.exports = express;
http
,创建进程监听端口const { createServer } = require("http");
listen
方法,监听端口class express {
listen(...args) {
createServer(cb).listen(...args);
}
}
class
的 listen
去调用 http
模块的 listen
了,这里的cb
我们可以先不管,你要知道每次接受到请求,必然会调用 cb
函数,这个是 createServer
原生模块帮我们封装好的app.get app.post
等方法class express {
cb() {
return (req, res) => {
console.log(res, res, "来客人了");
};
}
listen(...args) {
createServer(this.cb()).listen(...args);
}
}
req
和 res
正是我们想要的可读流和可写流.get
和 post
方法 constructor() {
this.routers = {
get: [],
post: [],
};
}
get(path, handle) {
this.routers.get.push({
path,
handle,
});
}
post(path, handle) {
this.routers.post.push({
path,
handle,
});
}
path
和 handle
.url
的 handle
方法,然后触发回调.url
对应的 handle
方法? 在接到请求时候就要遍历一次get
方式的 test
路由 cb() {
return (req, res) => {
const method = req.method.toLowerCase();
console.log(this.routers[method], ",method");
const url = req.url;
this.routers[method].forEach((item) => {
item.path === url && item.handle(req, res);
});
};
}
listen(...args) {
createServer(this.cb()).listen(...args);
}
[ { method: 'get', path: '/test', handle: [Function] } ] ,method
express
已经完成了,但是我们好像忘了最重要的中间件express
中间件分两种,一种带路由的,那就是根据路由决定是否触发all
数组储存这种任意路由都需要匹配触发的 constructor() {
this.routers = {
get: [],
post: [],
all: [],
};
}
get
、post
方法,定义handleAddRouter
方法 handleAddRouter(path, handle) {
let router = {};
if (typeof path === "string") {
router = {
path,
handle,
};
} else {
router = {
path: "/",
handle: path,
};
}
return router;
}
get(path, handle) {
const router = this.handleAddRouter(path, handle);
this.routers.get.push(router);
}
post(path, handle) {
const router = this.handleAddRouter(path, handle);
this.routers.post.push(router);
}
use(path, handle) {
const router = this.handleAddRouter(path, handle);
this.routers.all.push(router);
}
handleAddRouter
,如果是 path
为空的中间件,直接传入函数的,那么 path
帮它设置成'/'next
的实现,因为我们现在加了all
这个数组后,意味着可能有多个中间件,那么可能一次请求打过来,就要触发多个路由❝这里要注意,promise.then 源码实现和 express 的 next、以及 koa 的洋葱圈、redux 的中间件实现,有着一丁点相似,当你能真的领悟前后端框架源码时候,发现大都相似
❞
next
思路:
首先要找到所有匹配的路由
然后逐个执行(看 next
的调用)
定义search
方法,找到所有匹配的路由
search(method, url) {
const matchedList = [];
[...this.routers[method], ...this.routers.all].forEach((item) => {
item.path === url && matchedList.push(item.handle);
});
return matchedList;
}
cb() {
return (req, res) => {
const method = req.method.toLowerCase();
const url = req.url;
const matchedList = this.search(method, url);
};
}
matchedList
就是我们想要找到的所有路由next
,我们要将req ,res , matchedList
存入闭包中,定义handle
方法 handle(req, res, matchedList) {
const next = () => {
const midlleware = matchedList.shift();
if (midlleware) {
midlleware(req, res, next);
}
};
next();
}
cb() {
return (req, res) => {
const method = req.method.toLowerCase();
const url = req.url;
const matchedList = this.search(method, url);
this.handle(req, res, matchedList);
};
}
next
方法,只要手动调用 next
就会调用下一个匹配到的路由回调函数express
框架Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8