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
數據可視化方向,期待你的到來在看
和關注
. 咱們的技術團隊也會不斷產出原創文章, 一塊兒見證各位的成長