日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網營銷解決方案
使用Node.js實現(xiàn)一個express框架

手寫一個express系列

express的基本用法

 
 
 
  1. const express = require("express");  
  2. const app = express();  
  3. app.get("/test", (req, res, next) => {  
  4.   console.log("*1");  
  5. //   res.end("2");  
  6.   next();  
  7. });  
  8. app.get("/test", (req, res, next) => {  
  9.   console.log("*2");  
  10.   res.end("2");  
  11. });  
  12. app.listen(8888, (err) => {  
  13.   !err && console.log("監(jiān)聽成功");  
  14. }); 
  •  當我訪問localhost:8888/test時候,返回了:2,服務端打印了 
 
 
 
  1. *1  
  2. *2 
  •  從上面可以看到什么?
    •  express默認引入調用后返回一個app對象
    •  app.listen 會啟動進程監(jiān)聽端口
    •  每次收到請求,對應的url和method會觸發(fā)相應掛載在app上對應的回調函數(shù)
    •  調用 next 方法,會觸發(fā)下一個

一起來實現(xiàn)一個簡單的express框架

  •  定義屬于我們的express文件入口,這里使用class來實現(xiàn) 
 
 
 
  1. class express {  
  2. }  
  3. module.exports = express; 
  •  需要的原生模塊http,創(chuàng)建進程監(jiān)聽端口 
 
 
 
  1. const { createServer } = require("http"); 
  •  給 class 定義 listen 方法,監(jiān)聽端口 
 
 
 
  1. class express {  
  2.   listen(...args) {  
  3.     createServer(cb).listen(...args);  
  4.   }  
  •  這樣就可以通過調用 class 的 listen 去調用 http 模塊的 listen 了,這里的cb我們可以先不管,你要知道每次接受到請求,必然會調用 cb 函數(shù),這個是 createServer 原生模塊幫我們封裝好的

實現(xiàn)接收到請求觸發(fā)

  •  實現(xiàn)app.get app.post等方法
    •  目前我們接受到響應,就會觸發(fā) cb 這個回調函數(shù),那我們打印下,看看是什么參數(shù)? 
 
 
 
  1. class express {  
  2.   cb() {  
  3.     return (req, res) => {  
  4.       console.log(res, res, "開始行動");  
  5.     };  
  6.   }  
  7.   listen(...args) {  
  8.     createServer(this.cb()).listen(...args);  
  9.   }  
  •  發(fā)現(xiàn)此時的 req 和 res 正是我們想要的可讀流和可寫流.
  •  開始編寫 get 和 post 方法
    •  這里注意,有路由是'/'的,這種是不管任何路由都會觸發(fā)一次 
 
 
 
  1. constructor() {  
  2.     this.routers = {  
  3.       get: [],  
  4.       post: [],  
  5.     };  
  6.   }  
  7.   get(path, handle) {  
  8.     this.routers.get.push({  
  9.       path,  
  10.       handle,  
  11.     });  
  12.   }  
  13.   post(path, handle) {  
  14.     this.routers.post.push({  
  15.       path,  
  16.       handle,  
  17.     });  
  18.   } 
  •  初始化時候定義 get、post 的數(shù)組儲存對應的 path 和 handle.
  •  需要觸發(fā)路由回調的時候,首先要找到對應的請求方式下對應的 url 的 handle 方法,然后觸發(fā)回調.
  •  如何找到對應請求方式下的 url 對應的 handle 方法? 在接到請求時候就要遍歷一次
    •  這里要考慮匹配多個路由,意味著,我們可能遇到像最開始一樣,有兩個 get 方式的 test 路由 
 
 
 
  1. cb() {  
  2.   return (req, res) => {  
  3.     const method = req.method.toLowerCase();  
  4.     console.log(this.routers[method], ",method");  
  5.     const url = req.url;  
  6.     this.routers[method].forEach((item) => {  
  7.       item.path === url && item.handle(req, res);  
  8.     });  
  9.   };  
  10. }  
  11. listen(...args) {  
  12.   createServer(this.cb()).listen(...args);  
  •  上面根據 method 找到對應的數(shù)組,遍歷找到請求的路由,觸發(fā)回調,此時已經能正常返回數(shù)據了 
 
 
 
  1. [ { method: 'get', path: '/test', handle: [Function] } ] ,method 
  •  此時最簡單的express已經完成了,但是我們好像忘了最重要的中間件

完成最重要的中間件功能

  •  首先要知道,express中間件分兩種,一種帶路由的,那就是根據路由決定是否觸發(fā)
  •  另外一種就是不帶路由的,像靜態(tài)資源這種. 是用戶訪問任何路由都要觸發(fā)一次的
  •  那我們需要一個 all 數(shù)組儲存這種任意路由都需要匹配觸發(fā)的 
 
 
 
  1. constructor() {  
  2.    this.routers = {  
  3.      get: [],  
  4.      post: [],  
  5.      all: [],  
  6.    };  
  7.  } 
  •  之前的直接通過 push 方式是太粗暴.如果用戶需要中間件功能,不傳路由,那就要做特殊處理,這里通過一個中間函數(shù)處理下
  •  改造get、post方法,定義handleAddRouter方法 
 
 
 
  1. handleAddRouter(path, handle) {  
  2.    let router = {}; 
  3.     if (typeof path === "string") {  
  4.      router = {  
  5.        path,  
  6.        handle,  
  7.      };  
  8.    } else {  
  9.      router = {  
  10.        path: "/",  
  11.        handle: path, 
  12.      };  
  13.    }  
  14.    return router;  
  15.  }  
  16.  get(path, handle) {  
  17.    const router = this.handleAddRouter(path, handle);  
  18.    this.routers.get.push(router);  
  19.  }  
  20.  post(path, handle) {  
  21.    const router = this.handleAddRouter(path, handle);  
  22.    this.routers.post.push(router); 
  23.   }  
  24.  use(path, handle) {  
  25.    const router = this.handleAddRouter(path, handle);  
  26.    this.routers.all.push(router);  
  27.  } 
  •  每次添加之前,先觸發(fā)一次handleAddRouter,如果是 path 為空的中間件,直接傳入函數(shù)的,那么 path 幫它設置成'/'
  •  我們還遺留了一個點,next的實現(xiàn),因為我們現(xiàn)在加了all這個數(shù)組后,意味著可能有多個中間件,那么可能一次請求打過來,就要觸發(fā)多個路由

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

  •  閱讀我的文章,足以擊破所有前后端源碼.而且可以手寫出來, 我們只學最核心的,抓重點學習,野蠻生長!

實現(xiàn)next

  •  思路:
    •  首先要找到所有匹配的路由
    •  然后逐個執(zhí)行(看 next 的調用)
  •  定義search方法,找到所有匹配的路由 
 
 
 
  1. search(method, url) {  
  2.     const matchedList = [];  
  3.     [...this.routers[method], ...this.routers.all].forEach((item) => {  
  4.       item.path === url && matchedList.push(item.handle);  
  5.     });  
  6.     return matchedList;  
  7.   }  
  8.   cb() {  
  9.     return (req, res) => {  
  10.       const method = req.method.toLowerCase();  
  11.       const url = req.url;  
  12.       const matchedList = this.search(method, url);  
  13.     };  
  14.   } 
  •  matchedList就是我們想要找到的所有路由
  •  為了完成next,我們要將req ,res , matchedList存入閉包中,定義handle方法 
 
 
 
  1. handle(req, res, matchedList) {  
  2.    const next = () => {  
  3.      const midlleware = matchedList.shift();  
  4.      if (midlleware) {  
  5.        midlleware(req, res, next);  
  6.      }  
  7.    };  
  8.    next();  
  9.  }  
  10.  cb() {  
  11.    return (req, res) => {  
  12.      const method = req.method.toLowerCase();  
  13.      const url = req.url;  
  14.      const matchedList = this.search(method, url);  
  15.      this.handle(req, res, matchedList);  
  16.    };  
  17.  } 
  •  這樣我們就完成了next方法,只要手動調用 next 就會調用下一個匹配到的路由回調函數(shù)
  •  不到一百行代碼,就完成了這個簡單的express框架

寫在最后

  •  只要你根據我這些文章去認真自己實現(xiàn)一次,一年內拿個 P6 應該沒什么問題
  •  大道至簡,希望你能通過這些文章真的學到框架的原理,進而自己能寫出一些框架,走向更高的層級
  •  我是Peter,曾經 20 萬人超級群桌面軟件的架構師,現(xiàn)在就職于明源云,擔任分公司前端負責人,目前深圳這邊需要招聘兩位中高級前端,3D數(shù)據可視化方向,期待你的到來
  •  如果感覺本文對你有幫助,別忘了點個在看和關注. 我們的技術團隊也會不斷產出原創(chuàng)文章, 一起見證各位的成長 

名稱欄目:使用Node.js實現(xiàn)一個express框架
標題路徑:http://m.5511xx.com/article/ccdhjog.html