express系列express的基本用法const express = require("express");
const app = express();
app.get("/test", (req, res, next) => {
console.log("*1");
// res.end("2");
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
*2express默认引入调用后返回一个app对象app.listen 会启动进程监听端口url和method会触发相应挂载在app上对应的回调函数next 方法,会触发下一个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] } ] ,methodexpress已经完成了,但是我们好像忘了最重要的中间件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 的中间件实现,有着一丁点相似,当你能真的领悟前后端框架源码时候,发现大都相似
nextnext 的调用)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框架Peter,曾经 20 万人超级群桌面软件的架构师,现在就职于明源云,担任分公司前端负责人,目前深圳这边需要招聘两位中高级前端,3D数据可视化方向,期待你的到来在看和关注. 我们的技术团队也会不断产出原创文章, 一起见证各位的成长