溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Node.js中怎么實(shí)現(xiàn)一個(gè)express框架

發(fā)布時(shí)間:2021-07-20 16:31:57 來(lái)源:億速云 閱讀:167 作者:Leah 欄目:web開(kāi)發(fā)

本篇文章給大家分享的是有關(guān)Node.js中怎么實(shí)現(xiàn)一個(gè)express框架,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

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)聽(tīng)成功");  });
  •  當(dāng)我訪問(wèn)localhost:8888/test時(shí)候,返回了:2,服務(wù)端打印了 

*1  *2
  •  從上面可以看到什么?

    •  express默認(rèn)引入調(diào)用后返回一個(gè)app對(duì)象

    •  app.listen 會(huì)啟動(dòng)進(jìn)程監(jiān)聽(tīng)端口

    •  每次收到請(qǐng)求,對(duì)應(yīng)的url和method會(huì)觸發(fā)相應(yīng)掛載在app上對(duì)應(yīng)的回調(diào)函數(shù)

    •  調(diào)用 next 方法,會(huì)觸發(fā)下一個(gè)

一起來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的express框架

  •  定義屬于我們的express文件入口,這里使用class來(lái)實(shí)現(xiàn) 

class express {  }  module.exports = express;
  •  需要的原生模塊http,創(chuàng)建進(jìn)程監(jiān)聽(tīng)端口 

const { createServer } = require("http");
  •  給 class 定義 listen 方法,監(jiān)聽(tīng)端口 

class express {    listen(...args) {      createServer(cb).listen(...args);    }  }
  •  這樣就可以通過(guò)調(diào)用 class 的 listen 去調(diào)用 http 模塊的 listen 了,這里的cb我們可以先不管,你要知道每次接受到請(qǐng)求,必然會(huì)調(diào)用 cb 函數(shù),這個(gè)是 createServer 原生模塊幫我們封裝好的

實(shí)現(xiàn)接收到請(qǐng)求觸發(fā)

  •  實(shí)現(xiàn)app.get app.post等方法

    •  目前我們接受到響應(yīng),就會(huì)觸發(fā) cb 這個(gè)回調(diào)函數(shù),那我們打印下,看看是什么參數(shù)? 

class express {    cb() {      return (req, res) => {        console.log(res, res, "開(kāi)始行動(dòng)");      };    }    listen(...args) {      createServer(this.cb()).listen(...args);    }  }
  •  發(fā)現(xiàn)此時(shí)的 req 和 res 正是我們想要的可讀流和可寫(xiě)流.

  •  開(kāi)始編寫(xiě) get 和 post 方法

    •  這里注意,有路由是'/'的,這種是不管任何路由都會(huì)觸發(fā)一次 

constructor() {      this.routers = {        get: [],        post: [],      };    }    get(path, handle) {      this.routers.get.push({        path,        handle,      });    }    post(path, handle) {      this.routers.post.push({        path,        handle,      });    }
  •  初始化時(shí)候定義 get、post 的數(shù)組儲(chǔ)存對(duì)應(yīng)的 path 和 handle.

  •  需要觸發(fā)路由回調(diào)的時(shí)候,首先要找到對(duì)應(yīng)的請(qǐng)求方式下對(duì)應(yīng)的 url 的 handle 方法,然后觸發(fā)回調(diào).

  •  如何找到對(duì)應(yīng)請(qǐng)求方式下的 url 對(duì)應(yīng)的 handle 方法? 在接到請(qǐng)求時(shí)候就要遍歷一次

    •  這里要考慮匹配多個(gè)路由,意味著,我們可能遇到像最開(kāi)始一樣,有兩個(gè) 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 找到對(duì)應(yīng)的數(shù)組,遍歷找到請(qǐng)求的路由,觸發(fā)回調(diào),此時(shí)已經(jīng)能正常返回?cái)?shù)據(jù)了 

[ { method: 'get', path: '/test', handle: [Function] } ] ,method
  •  此時(shí)最簡(jiǎn)單的express已經(jīng)完成了,但是我們好像忘了最重要的中間件

完成最重要的中間件功能

  •  首先要知道,express中間件分兩種,一種帶路由的,那就是根據(jù)路由決定是否觸發(fā)

  •  另外一種就是不帶路由的,像靜態(tài)資源這種. 是用戶訪問(wèn)任何路由都要觸發(fā)一次的

  •  那我們需要一個(gè) all 數(shù)組儲(chǔ)存這種任意路由都需要匹配觸發(fā)的 

constructor() {     this.routers = {       get: [],       post: [],       all: [],     };   }
  •  之前的直接通過(guò) push 方式是太粗暴.如果用戶需要中間件功能,不傳路由,那就要做特殊處理,這里通過(guò)一個(gè)中間函數(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è)置成'/'

  •  我們還遺留了一個(gè)點(diǎn),next的實(shí)現(xiàn),因?yàn)槲覀儸F(xiàn)在加了all這個(gè)數(shù)組后,意味著可能有多個(gè)中間件,那么可能一次請(qǐng)求打過(guò)來(lái),就要觸發(fā)多個(gè)路由

這里要注意,promise.then 源碼實(shí)現(xiàn)和 express 的 next、以及 koa 的洋蔥圈、redux 的中間件實(shí)現(xiàn),有著一丁點(diǎn)相似,當(dāng)你能真的領(lǐng)悟前后端框架源碼時(shí)候,發(fā)現(xiàn)大都相似

  •  閱讀我的文章,足以擊破所有前后端源碼.而且可以手寫(xiě)出來(lái), 我們只學(xué)最核心的,抓重點(diǎn)學(xué)習(xí),野蠻生長(zhǎng)!

實(shí)現(xiàn)next

  •  思路:

    •  首先要找到所有匹配的路由

    •  然后逐個(gè)執(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方法,只要手動(dòng)調(diào)用 next 就會(huì)調(diào)用下一個(gè)匹配到的路由回調(diào)函數(shù)

  •  不到一百行代碼,就完成了這個(gè)簡(jiǎn)單的express框架

以上就是Node.js中怎么實(shí)現(xiàn)一個(gè)express框架,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI