掌握 Express.js:深入探討
Express 是 Node.js 中極為常用的 Web 伺服器應用程式框架。本質上,框架是一種遵循特定規則的程式碼結構,具有兩個關鍵特徵:
- 封裝了API,讓開發者更專注於業務程式碼的撰寫。
- 已建立流程和標準規格。
Express框架的核心特性如下:
- 它可以設定中間件來回應各種HTTP請求。
- 它定義了一個路由表,用於執行不同類型的HTTP請求操作。
- 支援傳遞給範本參數,實現HTML頁面的動態渲染。
本文將透過實作一個簡單的 LikeExpress 類別來分析 Express 如何實現中介軟體註冊、下一個機制以及路由處理。
快速分析
我們先透過兩個 Express 程式碼範例來探索它提供的功能:
Express 官網 Hello World 範例
const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`); });
入口檔app.js分析
以下是express-generator腳手架產生的Express專案的入口檔案app.js的程式碼:
// Handle errors caused by unmatched routes const createError = require('http-errors'); const express = require('express'); const path = require('path'); const indexRouter = require('./routes/index'); const usersRouter = require('./routes/users'); // `app` is an Express instance const app = express(); // View engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // Parse JSON format data in post requests and add the `body` field to the `req` object app.use(express.json()); // Parse the urlencoded format data in post requests and add the `body` field to the `req` object app.use(express.urlencoded({ extended: false })); // Static file handling app.use(express.static(path.join(__dirname, 'public'))); // Register top-level routes app.use('/', indexRouter); app.use('/users', usersRouter); // Catch 404 errors and forward them to the error handler app.use((req, res, next) => { next(createError(404)); }); // Error handling app.use((err, req, res, next) => { // Set local variables to display error messages in the development environment res.locals.message = err.message; // Decide whether to display the full error according to the environment variable. Display in development, hide in production. res.locals.error = req.app.get('env') === 'development'? err : {}; // Render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
從上面兩段程式碼可以看出,Express實例應用程式主要有三個核心方法:
-
app.use([path,]callback[,callback...]):用來註冊中間件。當請求路徑符合設定的規則時,就會執行對應的中介軟體函數。
- path:指定呼叫中間件函數的路徑。
- 回調:回呼函數可以採用多種形式。它可以是單一中間件函數、一系列以逗號分隔的中間件函數、中間件函數陣列或以上所有函數的組合。
- app.get() 和 app.post():這些方法與 use() 類似,也是用來註冊中間件。但是,它們綁定到 HTTP 請求方法。只有使用對應的HTTP請求方法才會觸發相關中間件的註冊。
- app.listen():負責建立一個httpServer並傳遞server.listen()所需的參數。
程式碼實現
透過對Express程式碼功能的分析,我們知道Express的實現重點在於三點:
- 中間件函數的註冊過程。
- 中介軟體功能中的核心next機制。
- 路由處理,重點是路徑匹配。
基於這些點,我們將在下面實作一個簡單的 LikeExpress 類別。
1. 類別的基本結構
首先明確指出該類別需要實作的主要方法:
- use():實作通用中間件註冊。
- get() 和 post():實作HTTP請求相關的中間件註冊。
- Listen():本質上就是httpServer的listen()函式。在該類別的listen()函數中,建立了一個httpServer,傳入參數,監聽請求,回呼函數(req, res) => {} 已執行。
回顧原生Node httpServer的使用:
const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`); });
相應地,LikeExpress類別的基本結構如下:
// Handle errors caused by unmatched routes const createError = require('http-errors'); const express = require('express'); const path = require('path'); const indexRouter = require('./routes/index'); const usersRouter = require('./routes/users'); // `app` is an Express instance const app = express(); // View engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // Parse JSON format data in post requests and add the `body` field to the `req` object app.use(express.json()); // Parse the urlencoded format data in post requests and add the `body` field to the `req` object app.use(express.urlencoded({ extended: false })); // Static file handling app.use(express.static(path.join(__dirname, 'public'))); // Register top-level routes app.use('/', indexRouter); app.use('/users', usersRouter); // Catch 404 errors and forward them to the error handler app.use((req, res, next) => { next(createError(404)); }); // Error handling app.use((err, req, res, next) => { // Set local variables to display error messages in the development environment res.locals.message = err.message; // Decide whether to display the full error according to the environment variable. Display in development, hide in production. res.locals.error = req.app.get('env') === 'development'? err : {}; // Render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
2. 中介軟體註冊
從 app.use([path,]callback[,callback...]) 中,我們可以看到中間件可以是函數數組,也可以是單一函數。為了簡化實現,我們將中間件統一處理為函數數組。 LikeExpress類別中use()、get()、post()這三個方法都可以實作中間件註冊。只是因為請求方式不同,觸發的中間件有所不同。所以我們考慮:
- 抽像出一個通用的中間件註冊函數。
- 為這三個方法建立中間件函數數組,用於儲存不同請求對應的中間件。由於use()是所有請求的通用中間件註冊方法,因此儲存use()中間件的陣列是get()和post()數組的並集。
中介軟體隊列數組
中間件數組需要放置在公共區域,以便於類別中的方法存取。所以,我們把中間件數組放在constructor()建構子中。
const http = require("http"); const server = http.createServer((req, res) => { res.end("hello"); }); server.listen(3003, "127.0.0.1", () => { console.log("node service started successfully"); });
中介軟體註冊功能
中間件註冊是指將中介軟體儲存在對應的中間件陣列中。中間件註冊函數需要解析傳入的參數。第一個參數可能是路由,也可能是中介軟體,所以需要先判斷是否為路由。如果是,則原樣輸出;否則預設為根路由,然後將剩餘的中間件參數轉為數組。
const http = require('http'); class LikeExpress { constructor() {} use() {} get() {} post() {} // httpServer callback function callback() { return (req, res) => { res.json = function (data) { res.setHeader('content-type', 'application/json'); res.end(JSON.stringify(data)); }; }; } listen(...args) { const server = http.createServer(this.callback()); server.listen(...args); } } module.exports = () => { return new LikeExpress(); };
use()、get() 和 post() 的實現
透過通用的中間件註冊函數register(),很容易實作use()、get()、post(),只需將中間件儲存在對應的陣列中即可。
const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`); });
3. 路由匹配處理
當註冊函數的第一個參數是路由時,只有當請求路徑匹配該路由或是其子路由時,才會觸發對應的中間件函數。所以,我們需要一個路由匹配函數,根據請求方法和請求路徑提取匹配路由的中間件數組,供後續的callback()函數執行:
// Handle errors caused by unmatched routes const createError = require('http-errors'); const express = require('express'); const path = require('path'); const indexRouter = require('./routes/index'); const usersRouter = require('./routes/users'); // `app` is an Express instance const app = express(); // View engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // Parse JSON format data in post requests and add the `body` field to the `req` object app.use(express.json()); // Parse the urlencoded format data in post requests and add the `body` field to the `req` object app.use(express.urlencoded({ extended: false })); // Static file handling app.use(express.static(path.join(__dirname, 'public'))); // Register top-level routes app.use('/', indexRouter); app.use('/users', usersRouter); // Catch 404 errors and forward them to the error handler app.use((req, res, next) => { next(createError(404)); }); // Error handling app.use((err, req, res, next) => { // Set local variables to display error messages in the development environment res.locals.message = err.message; // Decide whether to display the full error according to the environment variable. Display in development, hide in production. res.locals.error = req.app.get('env') === 'development'? err : {}; // Render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
然後,在httpServer的回呼函數callback()中,提取出需要執行的中間件:
const http = require("http"); const server = http.createServer((req, res) => { res.end("hello"); }); server.listen(3003, "127.0.0.1", () => { console.log("node service started successfully"); });
四、下一個機制的實施
Express中間件函數的參數為req、res、next,其中next是一個函數。只有呼叫它,中間件函數才能依序執行,類似ES6 Generator中的next()。在我們的實作中,我們需要寫一個具有以下要求的 next() 函數:
- 每次從中間件佇列數組中依序擷取一個中間件。
- 將 next() 函數傳遞到擷取的中間件。由於中間件數組是公共的,因此每次執行next()時,都會取出數組中的第一個中間件函數執行,從而達到中間件順序執行的效果。
const http = require('http'); class LikeExpress { constructor() {} use() {} get() {} post() {} // httpServer callback function callback() { return (req, res) => { res.json = function (data) { res.setHeader('content-type', 'application/json'); res.end(JSON.stringify(data)); }; }; } listen(...args) { const server = http.createServer(this.callback()); server.listen(...args); } } module.exports = () => { return new LikeExpress(); };
快速程式碼
constructor() { // List of stored middleware this.routes = { all: [], // General middleware get: [], // Middleware for get requests post: [], // Middleware for post requests }; }
Leapcell:用於 Web 託管、非同步任務和 Redis 的下一代無伺服器平台
最後要介紹一個非常適合部署Express的平台:Leapcell。
Leapcell 是無伺服器平台,具有以下特性:
1. 多語言支持
- 使用 JavaScript、Python、Go 或 Rust 進行開發。
2.免費部署無限個項目
- 只需支付使用費用-無請求,不收費。
3. 無與倫比的成本效益
- 即用即付,無閒置費用。
- 範例:25 美元支援 694 萬個請求,平均回應時間為 60 毫秒。
4.簡化的開發者體驗
- 直覺的使用者介面,輕鬆設定。
- 完全自動化的 CI/CD 管道和 GitOps 整合。
- 即時指標和日誌記錄以獲取可行的見解。
5. 輕鬆的可擴充性和高效能
- 自動擴充以輕鬆處理高並發。
- 零營運開銷-只需專注於建置。
在文件中探索更多內容!
Leapcell Twitter:https://x.com/LeapcellHQ
以上是掌握 Express.js:深入探討的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務
