express
系列express
的基本用法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
从上面能够看到什么?前端
express
默认引入调用后返回一个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
等方法express
class express { cb() { return (req, res) => { console.log(res, res, "来客人了"); }; } listen(...args) { createServer(this.cb()).listen(...args); } }
req
和 res
正是咱们想要的可读流和可写流.开始编写 get
和 post
方法redux
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
框架Peter
,曾经 20 万人超级群桌面软件的架构师,如今就任于明源云,担任分公司前端负责人,目前深圳这边须要招聘两位中高级前端,3D
数据可视化方向,期待你的到来在看
和关注
. 咱们的技术团队也会不断产出原创文章, 一块儿见证各位的成长