本篇文章給大家分享的是有關(guān)Node.js中怎么實現(xiàn)一個express框架,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
成都創(chuàng)新互聯(lián)公司主營松滋網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶APP軟件開發(fā),松滋h5小程序開發(fā)搭建,松滋網(wǎng)站營銷推廣歡迎松滋等地區(qū)企業(yè)咨詢
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("監(jiān)聽成功"); });
當(dāng)我訪問localhost:8888/test時候,返回了:2,服務(wù)端打印了
*1 *2
從上面可以看到什么?
express默認(rèn)引入調(diào)用后返回一個app對象
app.listen 會啟動進(jìn)程監(jiān)聽端口
每次收到請求,對應(yīng)的url和method會觸發(fā)相應(yīng)掛載在app上對應(yīng)的回調(diào)函數(shù)
調(diào)用 next 方法,會觸發(fā)下一個
一起來實現(xiàn)一個簡單的express框架
定義屬于我們的express文件入口,這里使用class來實現(xiàn)
class express { } module.exports = express;
需要的原生模塊http,創(chuàng)建進(jìn)程監(jiān)聽端口
const { createServer } = require("http");
給 class 定義 listen 方法,監(jiān)聽端口
class express { listen(...args) { createServer(cb).listen(...args); } }
這樣就可以通過調(diào)用 class 的 listen 去調(diào)用 http 模塊的 listen 了,這里的cb我們可以先不管,你要知道每次接受到請求,必然會調(diào)用 cb 函數(shù),這個是 createServer 原生模塊幫我們封裝好的
實現(xiàn)接收到請求觸發(fā)
實現(xiàn)app.get app.post等方法
目前我們接受到響應(yīng),就會觸發(fā) cb 這個回調(diào)函數(shù),那我們打印下,看看是什么參數(shù)?
class express { cb() { return (req, res) => { console.log(res, res, "開始行動"); }; } listen(...args) { createServer(this.cb()).listen(...args); } }
發(fā)現(xiàn)此時的 req 和 res 正是我們想要的可讀流和可寫流.
開始編寫 get 和 post 方法
這里注意,有路由是'/'的,這種是不管任何路由都會觸發(fā)一次
constructor() { this.routers = { get: [], post: [], }; } get(path, handle) { this.routers.get.push({ path, handle, }); } post(path, handle) { this.routers.post.push({ path, handle, }); }
初始化時候定義 get、post 的數(shù)組儲存對應(yīng)的 path 和 handle.
需要觸發(fā)路由回調(diào)的時候,首先要找到對應(yīng)的請求方式下對應(yīng)的 url 的 handle 方法,然后觸發(fā)回調(diào).
如何找到對應(yīng)請求方式下的 url 對應(yīng)的 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); }
上面根據(jù) method 找到對應(yīng)的數(shù)組,遍歷找到請求的路由,觸發(fā)回調(diào),此時已經(jīng)能正常返回數(shù)據(jù)了
[ { method: 'get', path: '/test', handle: [Function] } ] ,method
此時最簡單的express已經(jīng)完成了,但是我們好像忘了最重要的中間件
完成最重要的中間件功能
首先要知道,express中間件分兩種,一種帶路由的,那就是根據(jù)路由決定是否觸發(fā)
另外一種就是不帶路由的,像靜態(tài)資源這種. 是用戶訪問任何路由都要觸發(fā)一次的
那我們需要一個 all 數(shù)組儲存這種任意路由都需要匹配觸發(fā)的
constructor() { this.routers = { get: [], post: [], all: [], }; }
之前的直接通過 push 方式是太粗暴.如果用戶需要中間件功能,不傳路由,那就要做特殊處理,這里通過一個中間函數(shù)處理下
改造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); }
每次添加之前,先觸發(fā)一次handleAddRouter,如果是 path 為空的中間件,直接傳入函數(shù)的,那么 path 幫它設(shè)置成'/'
我們還遺留了一個點(diǎn),next的實現(xiàn),因為我們現(xiàn)在加了all這個數(shù)組后,意味著可能有多個中間件,那么可能一次請求打過來,就要觸發(fā)多個路由
這里要注意,promise.then 源碼實現(xiàn)和 express 的 next、以及 koa 的洋蔥圈、redux 的中間件實現(xiàn),有著一丁點(diǎn)相似,當(dāng)你能真的領(lǐng)悟前后端框架源碼時候,發(fā)現(xiàn)大都相似
閱讀我的文章,足以擊破所有前后端源碼.而且可以手寫出來, 我們只學(xué)最核心的,抓重點(diǎn)學(xué)習(xí),野蠻生長!
實現(xiàn)next
思路:
首先要找到所有匹配的路由
然后逐個執(zhí)行(看 next 的調(diào)用)
定義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方法,只要手動調(diào)用 next 就會調(diào)用下一個匹配到的路由回調(diào)函數(shù)
不到一百行代碼,就完成了這個簡單的express框架
以上就是Node.js中怎么實現(xiàn)一個express框架,小編相信有部分知識點(diǎn)可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。