【Express】中介軟體 - AOP - 應用程式級別 - 路由級別 - 錯誤處理 - 內建 - 第三方
theme: fancy highlight: a11y-dark
小知識,大挑戰!本文正在參與“程式設計師必備小知識”創作活動。
本文已參與「掘力星計劃」,贏取創作大禮包,挑戰創作激勵金。
嗨!~ 大家好,我是YK菌 🐷 ,一個微系前端 ✨,喜歡分享自己學到的小知識 🏹,歡迎關注我呀 😘 ~ [微訊號: yk2012yk2012,微信公眾號:ykyk2012]
之前我們對Express進行了一個入門,今天來學習Express中介軟體相關內容,先介紹一些內建中介軟體的使用,後面我們做小demo的時候再用一些第三方中介軟體.
1. 示例
需求:輸出請求日誌
javascript
app.get("/", (req, res) => {
console.log(req.method, req.url, Date.now());
res.send("get /");
});
如果要給每個路由都輸出請求日誌,我們可以封裝在一個函式中
javascript
const myLooger = (req) => {
console.log(req.method, req.url, Date.now());
};
app.get("/", (req, res) => {
myLooger(req);
res.send("get /");
});
但是我們不想修改每一個路由,可以用中介軟體
【任何請求都會使用這個中介軟體】
```javascript
// req 請求物件
// res 響應物件
// next 下一個中介軟體
app.use((req, res, next) => {
console.log(req.method, req.url, Date.now())
// 交出執行權,往後繼續匹配執行
next()
})
app.get("/", (req, res) => { res.send("get /"); }); ```
中介軟體的順序很重要【從上往下】 【路由】也是一種【中介軟體】
2. 概念解析
2.1 中介軟體與AOP
Express的最大特色,也是最重要的一個設計,就是中介軟體。
在不修改原有程式碼的基礎上,增加一些新的功能
一個Express應用,就是由許許多多的中介軟體來完成的。
Express中介軟體類似於AOP面向切面程式設計 都是需要經過一些步驟,不用去修改自己的程式碼,從此來拓展或處理一些功能
- AOP(Aspect Oriented Programming)面向切面程式設計
- 將日誌記錄,效能統計、安全控制、事務處理、異常處理等程式碼從業務邏輯程式碼中劃分出來,通過對這些行為的分離,希望可以將它們獨立到非指導業務邏輯的方法中,進而改變這些行為的時候不影響業務邏輯的程式碼
- 利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性同時提高了開發的效率和可維護性
總結:在現有的程式碼程式中,在程式生命週期或者橫向流程中,加入/減去一個或多個功能,不影響原有功能。
2.2 Express中的中介軟體
在Express中,中介軟體就是一個可以訪問請求物件、響應物件和呼叫next方法的一個函式
在中介軟體函式中,可以執行以下任何任務
- 執行任何程式碼
- 修改 request
或 response
響應物件【同一個生命週期】
- 結束請求響應週期
- 呼叫下一個中介軟體
【注意】如果當前的中介軟體功能沒有結束請求-響應週期,則必須呼叫next()
將控制全傳遞給下一個中介軟體功能。否則,該請求將被掛起
3. 詳細使用
在Express中應用程式可以使用以下型別的中介軟體 - 應用程式級別中介軟體 - 路由級別中介軟體 - 錯誤處理中介軟體 - 內建中介軟體 - 第三方中介軟體
3.1 應用程式級別中介軟體
不關心請求路徑
javascript
app.use((req, res, next) => {
console.log("Time", Date.now());
next();
});
限定請求路徑
javascript
app.use('/user/:id',(req, res, next) => {
console.log("Request Type", req.method); // GET
next();
});
限定請求方法+請求路徑【路由中介軟體】
javascript
app.get('/user/:id',(req, res, next) => {
res.send('Hello World')
});
多個處理函式
javascript
app.use(
"/user/:id",
(req, res, next) => {
console.log("Request URL", req.originalUrl);
next();
},
(req, res, next) => {
console.log("Request Type", req.method);
next();
}
);
為同一個路徑定義多個處理中介軟體
```javascript app.get( "/user/:id", (req, res, next) => { console.log("ID", req.params.id); next(); }, (req, res, next) => { res.send("User Info"); next(); } );
app.get("/user/:id", (req, res, next) => { console.log("123"); // res.end(req.params.id); }); ```
要從路由器中介軟體堆疊中跳過其餘中介軟體功能,請呼叫next('route')
將控制權傳遞給下一條路由
【注意】next('route')
僅在使用app.METHOD()
或router.METHOD()
函式載入的中間函式中有效
此示例顯示了一箇中間件子堆疊,該子堆疊處理對/user/:id
路徑的GET請求
```javascript
app.get(
"/user/:id",
(req, res, next) => {
if (req.params.id === "0") next("route");
else next();
},
(req, res, next) => {
res.send("regular");
}
);
app.get("/user/:id", (req, res, next) => { res.send("special"); }); ```
中介軟體也可以在【陣列】中宣告為可重用。
此示例顯示了一個帶有中介軟體子堆疊的陣列,該子堆疊處理對/user/:id
路徑的GET請求
```javascript function logOriginalUrl(req, res, next) { console.log("Request URL", req.originalUrl); next(); } function logMethod(req, res, next) { console.log("Requset Type", req.method); next(); } const logStuff = [logOriginalUrl, logMethod];
app.get("/user/:id", logStuff, (req, res, next) => { res.send("User Info"); }); ```
3.2 路由級別中介軟體
建立路由器檔案
router.js ```javascript const express = require('express')
// 1. 建立路由例項 // 路由例項相當於一個 mini Express例項 const router = express.Router()
// 2. 配置路由 router.get('/user', (req, res) => { res.send('get /user') })
router.post('/user/:id', (req, res) => {
res.send(post /user/${req.params.id}
)
})
// 3. 匯出路由例項 // export default router module.exports = router
// 4. 將路由整合到 Express例項中[掛載]
app.js
javascript
const express = require("express");
const router = require('./router')
const app = express(); const port = 3000; // 預設3000
// 4. 掛載路由 app.use(router) app.use('/yk', router)
app.listen(port, () => {
console.log(Server running at http://localhost:${port}/
);
});
```
3.3 錯誤處理中介軟體
錯誤處理【匹配到了出現錯誤呼叫next(err)】
定義錯誤處理中介軟體函式,使用四個引數
一般是在所有中介軟體之後掛載錯誤處理中介軟體
javascript
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).send('Something broke!')
})
錯誤處理中介軟體始終帶有四個引數,必須提供四個引數,即使不需要next
也要指定它,否則,將會解釋成常規中介軟體,並且無法處理錯誤
如果將任何內容傳遞給該next()
函式('route'
除外),Express都會將當前請求視為錯誤,並且將跳過所有剩餘的非錯誤處理路由和中介軟體函式
```javascript app.get("/todos", async (req, res, next) => { try { const db = await getDb(); res.status(200).json(db.todos); } catch (err) { // 跳過所有剩餘的無錯誤處理路由和中間函式 next(err); } });
app.use((err, req, res, next) => { console.log("錯誤", err); res.status(500).json({ error: err.message, }); }); ```
處理404【路由匹配不到情況】
通常會在所有的路由之後配置處理 404 的內容
javascript
app.use((req, res, next) => {
res.status(404).send("404 Not Found.");
});
3.4 內建中介軟體
express.json()
解析Content-Type為application/json
格式的請求體express.urlencoded()
解析Content-Type 為application/x-www-form-urlencoded
格式的請求體express.raw()
解析Content-Type為application/octet-stream
格式的請求體express.text()
解析Content-Type為text/plain
格式的請求體express.static()
託管靜態資原始檔
3.5 第三方中介軟體
早期的Express內建了很多中介軟體。後來Express在4.x之後移除了這些內建中介軟體,官方把這些功能中介軟體以包的形式提供出來。這樣做的目的是為了保持Express本身極簡靈活的特性,開發人員可以根據自己的需要去靈活的使用。
https://www.expressjs.com.cn/resources/middleware.html
參考影片: Express 教程(基礎+實戰+原理)
- 【TS】快速上手(四)配置選項 - 編譯選項compilerOptions
- 【LeetCode】圖解反轉連結串列 - 迭代 - 遞迴
- 【LeetCode】最大子序和從O(N^3)到O(N) - 暴力初探 - 分而治之 - 線上處理
- 【JS】JavaScript基礎知識自我檢查大過關(第三關)函式定義與呼叫
- 【Vue】高階系列(六)Vue-cli配置代理 -demo3-GitHub使用者查詢-axios
- 【Vue】高階系列(五)元件間通訊
- 【Vue】高階系列(四)Vue模組化實戰-demo2-任務清單todoList
- 【TS】快速上手(二)型別宣告
- 【Vue】高階系列(三)Vue模組化實戰-demo1-動態評價頁面
- 【Vue】高階系列(二)Vue相關小知識
- 【Vue】高階系列(一)Vue元件定義與使用 - 非單檔案元件 - 單檔案元件 - VueComponent
- 【Vue】基礎系列(十一)Vue指令-常用內建指令-自定義指令-全域性指令-區域性指令
- 【Vue】基礎系列(九)動畫與過渡-trasition-enter-leave
- 【Vue】基礎系列(八)生命週期 - 初始化顯示 - 更新狀態 - 死亡狀態 - 父子元件
- 【Vue】基礎系列(七)v-model - 自動收集資料 - 表單資料自動更新
- 【Vue】基礎系列(六)事件處理 - 繫結監聽 - 事件修飾符 - 按鍵修飾符
- 【Vue】基礎系列(四)樣式繫結 - class - style
- 【Vue】基礎系列(二)模板語法 - 插值語法 - 指令語法 - | v-bind | v-model | v-on | v-if | v- show
- 【Vue】實戰專案:電商後臺管理系統(九)專案優化 上線
- 【Vue】實戰專案:電商後臺管理系統(八)資料統計模組