Express中間件(Middleware)詳解:從零開始掌握(2)

1. 請求耗時中間件的增強版

問題:原版只能記錄到控制臺,如何記錄到文件?

改進點

  1. 使用process.hrtime()是什么?獲取更高精度的時間
  2. 支持將日志寫入文件
  3. 記錄更多信息(IP地址、狀態碼)
  4. 工廠函數模式使中間件可配置
const fs = require('fs');
const path = require('path');// 增強版耗時記錄中間件
function createRequestLogger(logFilePath) {const logStream = fs.createWriteStream(path.join(__dirname, logFilePath), { flags: 'a' });return (req, res, next) => {const start = process.hrtime();const startDate = new Date().toISOString();res.on('finish', () => {const duration = process.hrtime(start);const durationMs = (duration[0] * 1e3 + duration[1] / 1e6).toFixed(3);const logEntry = `[${startDate}] ${req.ip} ${req.method} ${req.url} ${res.statusCode} ${durationMs}ms\n`;logStream.write(logEntry);console.log(logEntry.trim());});next();};
}// 使用方式
app.use(createRequestLogger('requests.log'));

2. API密鑰驗證中間件的進階版

問題:如何支持多種驗證方式?

改進點

  1. 支持多種認證策略(API Key、JWT、Basic Auth)
  2. 異步驗證支持
  3. 統一的錯誤處理
  4. 可擴展的工廠函數設計
// 支持多種驗證策略的中間件工廠
function createAuthMiddleware(options = {}) {return async (req, res, next) => {try {// 策略1: API Key驗證if (options.apiKey) {const apiKey = req.headers['x-api-key'] || req.query.apiKey;if (!apiKey) throw new Error('Missing API key');if (!options.apiKey.keys.includes(apiKey)) throw new Error('Invalid API key');req.authType = 'apiKey';}// 策略2: JWT驗證if (options.jwt) {const token = req.headers.authorization?.split(' ')[1];if (!token) throw new Error('Missing token');const decoded = await verifyJWT(token, options.jwt.secret);req.user = decoded;req.authType = 'jwt';}// 策略3: 基本認證if (options.basicAuth) {const authHeader = req.headers.authorization;if (!authHeader || !authHeader.startsWith('Basic ')) {throw new Error('Missing basic auth');}const credentials = Buffer.from(authHeader.split(' ')[1], 'base64').toString();const [username, password] = credentials.split(':');if (username !== options.basicAuth.user || password !== options.basicAuth.pass) {throw new Error('Invalid credentials');}req.authType = 'basic';}next();} catch (error) {res.status(401).json({ error: 'Authentication failed',message: error.message});}};
}// 使用示例
app.use(createAuthMiddleware({apiKey: {keys: ['123-abc', '456-def']},jwt: {secret: 'my-secret-key'}
}));

3. 組合中間件的模式進階

問題:如何更靈活地組合中間件?

改進點

  1. 實現了類似Koa的中間件組合機制
  2. 添加條件中間件支持
  3. 更靈活的路徑匹配
  4. 錯誤處理集成
// 中間件組合工具函數
function composeMiddlewares(...middlewares) {return (req, res, next) => {const dispatch = (i) => {if (i >= middlewares.length) return next();const middleware = middlewares[i];try {return middleware(req, res, () => dispatch(i + 1));} catch (err) {return next(err);}};return dispatch(0);};
}// 條件中間件
function conditionalMiddleware(condition, middleware) {return (req, res, next) => {if (condition(req)) {return middleware(req, res, next);}next();};
}// 使用示例
const isAdminRoute = req => req.path.startsWith('/admin');
const isApiRoute = req => req.path.startsWith('/api');app.use(composeMiddlewares(requestLogger,conditionalMiddleware(isApiRoute,apiKeyValidator),conditionalMiddleware(isAdminRoute,adminCheck)
));// 等價于:
// app.use(requestLogger);
// app.use('/api', apiKeyValidator);
// app.use('/admin', adminCheck);

實用中間件模式

1. 數據轉換中間件

function transformRequestBody(fields) {return (req, res, next) => {if (req.body) {for (const [field, transform] of Object.entries(fields)) {if (req.body[field] !== undefined) {req.body[field] = transform(req.body[field]);}}}next();};
}// 使用示例
app.use(express.json());
app.use(transformRequestBody({email: v => v.toLowerCase().trim(),age: v => parseInt(v, 10),isActive: v => v === 'true'
}));

2. 響應包裝中間件

function responseWrapper() {return (req, res, next) => {const originalSend = res.send;res.send = function(body) {if (res.statusCode >= 400) {originalSend.call(this, {success: false,error: body});} else {originalSend.call(this, {success: true,data: body});}};next();};
}

3. 請求限流中間件

function rateLimiter({ windowMs, maxRequests }) {const requests = new Map();setInterval(() => {requests.clear();}, windowMs);return (req, res, next) => {const ip = req.ip;const count = requests.get(ip) || 0;if (count >= maxRequests) {return res.status(429).send('Too many requests');}requests.set(ip, count + 1);next();};
}

最佳實踐建議

  1. ?單一職責:每個中間件只做一件事
  2. ?可重用性:設計為可配置的工廠函數
  3. ?錯誤處理:始終捕獲同步和異步錯誤
  4. ?性能考慮:避免在中間件中進行阻塞操作
  5. ?文檔注釋:清晰說明中間件的用途和參數。

本節就到這里,下節將繼續深入討論示例。

Express中間件(Middleware)詳解:從零開始掌握(3)-CSDN博客

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/76650.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/76650.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/76650.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何設置Ubuntu服務器版防火墻

在Ubuntu服務器中,默認使用 ufw(Uncomplicated Firewall)作為防火墻管理工具。它是對iptables的簡化封裝,適合快速配置防火墻規則。以下是設置防火墻的詳細步驟: 1. 安裝與啟用 ufw 安裝(通常已預裝&…

暢游Diffusion數字人(23):字節最新表情+動作模仿視頻生成DreamActor-M1

暢游Diffusion數字人(0):專欄文章導航 前言:之前有很多動作模仿或者表情模仿的工作,但是如果要在實際使用中進行電影級的復刻工作,僅僅表情或動作模仿還不夠,需要表情和動作一起模仿。最近字節跳動提出了一個表情+動作模仿視頻生成DreamActor-M1。 目錄 貢獻概述 核心動…

模型開發中的微調是干什么

在模型開發中,微調(Fine-tuning) 是指利用預訓練模型(Pre-trained Model)的參數作為初始值,在特定任務或數據集上進一步調整模型參數的過程。它是遷移學習(Transfer Learning)的核心…

vue3中,element-plus中el-select隱藏下拉箭頭

需求&#xff1a;el-select需要隱藏下拉箭頭 <el-select v-model"apply.dataType" readonly><el-option :key"1" label"樣品檢相同項目" :value"1" /><el-option :key"2" label"樣品檢不同項目" :…

英語學習4.9

cordial 形容詞&#xff1a; 熱情友好的&#xff0c;誠懇的 表示一個人態度溫和、親切&#xff0c;給人溫暖和善的感覺。 令人愉快的&#xff0c;和睦的 形容關系融洽、氛圍和諧。 例句??&#xff1a; The two leaders had a ??cordial?? but formal discussion. &am…

類似東郊到家的上門按摩預約服務系統小程序APP源碼全開源

&#x1f525; 為什么上門按摩正在席卷全國&#xff1f; 萬億藍海市場爆發 2024年中國按摩市場規模突破8000億&#xff0c;上門服務增速達65% 90后成消費主力&#xff0c;**72%**白領每月至少使用1次上門按摩&#xff08;數據來源&#xff1a;艾媒咨詢&#xff09; 傳統痛點…

驅動學習專欄--寫在前面

此專欄基于正點原子的文檔【正點原子】I.MX6U嵌入式Linux驅動開發指南V1.81 開發板為luckfox的rv1106開發板&#xff0c;之前參加過一個CM1相機的開源項目&#xff0c;與其吃灰不如作為一個學習的工具來發揮余熱 所以文檔中的一些東西需要對應的在rv1106平臺上做修改&#xff…

第二篇:Python函數與模塊化編程深度教程

第一章:函數定義與調用 1.1 函數基礎架構 1.1.1 函數定義規范 函數定義采用def關鍵字,遵循PEP8命名規范(小寫字母+下劃線) def calculate_circle_area(radius):"""計算圓的面積""" # 文檔字符串PI = 3.14159return PI * radius ?**? …

3.1.3.3 Spring Boot使用Filter組件

在Spring Boot中使用Filter組件&#xff0c;可以通過創建一個類實現Filter接口&#xff0c;并使用Component注解將其標記為Spring組件。通過Order注解可以指定過濾器的執行順序&#xff0c;數字越小優先級越高。在LoggingFilter類中&#xff0c;重寫init、doFilter和destroy方法…

目標追蹤Hyperspectral Adapter for Object Tracking based on Hyperspectral Video

論文作者&#xff1a;Long Gao,Yunhe Zhang,Langkun Chen,Yan Jiang,Weiying Xie,Yunsong Li 作者單位&#xff1a;Xidian University;the University of Sheffield 論文鏈接&#xff1a;http://arxiv.org/abs/2503.22199v1 內容簡介&#xff1a; 1&#xff09;方向&#x…

Python及C++中的排序

一、Python中的排序 &#xff08;一&#xff09;內置排序函數sorted() 基本用法 sorted()函數可以對所有可迭代對象進行排序操作&#xff0c;返回一個新的列表&#xff0c;原列表不會被修改。例如&#xff0c;對于一個簡單的數字列表nums [3, 1, 4, 1, 5, 9, 2, 6]&#xff…

詳解springcloud nacos使用

1.nacos server安裝 下載 Nacos Server 2.5.1 https://nacos.io/download/nacos-server/?spm5238cd80.2ef5001f.0.0.3f613b7clM2t6D 部署文檔&#xff1a;https://nacos.io/docs/latest/manual/admin/deployment/deployment-standalone/?spm5238cd80.6a33be36.0.0.25b41e5d…

第三篇:Python數據結構深度解析與工程實踐

第一章:列表與字典 1.1 列表的工程級應用 1.1.1 動態數組實現機制 Python列表底層采用動態數組結構,初始分配8個元素空間,當空間不足時按0,4,8,16,25,35...的公式擴容,每次擴容增加約12.5%的容量 通過sys模塊可驗證擴容過程: import sys lst = [] prev_size = 0 for …

NOIP2015提高組.運輸計劃

目錄 題目算法標簽: 樹上倍增, l c a lca lca, 前綴和, 樹上差分, 二分思路代碼* v e c t o r vector vector存鄰接表會超時 題目 521. 運輸計劃 算法標簽: 樹上倍增, l c a lca lca, 前綴和, 樹上差分, 二分 思路 注意到答案是具有二分性質的, 對于某個時間 m i d mid …

MySQL數據過濾、轉換與標準化

數據處理是數據庫操作的重要組成部分&#xff0c;尤其是在大量數據中查找、轉換和規范化目標信息的過程中。為了確保數據的有效性與一致性&#xff0c;MySQL提供了一系列數據過濾、轉換與標準化的功能。 本教程將深入探討數據過濾和轉換的基本方法及應用&#xff0c;內容涵蓋數…

英語學習4.11

gear 【名詞 / 動詞】 &#x1f449; 關鍵詞&#xff1a;齒輪、裝備、調節、使適應 名詞釋義&#xff1a; 齒輪&#xff1a; 一種機械裝置&#xff0c;用于傳遞動力或調節運動。 裝備、工具&#xff1a; 指用于某種活動的設備或工具。 汽車檔位&#xff1a; 汽車中用于改變…

SDC命令詳解:使用相對路徑訪問設計對象(current_instance命令)

相關閱讀 SDC命令詳解https://blog.csdn.net/weixin_45791458/category_12931432.html?spm1001.2014.3001.5482 在使用get_cells等命令訪問設計對象時&#xff0c;需要指定設計對象的名字&#xff0c;這個名字是一個相對路徑&#xff0c;本文就將對此進行討論。 相對路徑 使…

【問題記錄】記錄2個安裝Centos/Anolis系統卡死在安裝包階段的問題?(硬盤分區?換設備)

背景 問題就不詳細記錄了&#xff0c;本文記錄的是Centos/Anolis安裝中卡主的問題。這個問題遇到過幾十次了&#xff0c;嘗試過各種方法。最近一個偶然因素找到了原因。然后翻看歷史上出現這個問題的照片居然是相同的地方卡死。。。 有點意思。特此記錄&#xff0c;希望未來遇…

微信小程序中的openid的作用

微信小程序中的openid的作用 引言 在當今數字化時代&#xff0c;用戶體驗成為了產品成功與否的關鍵因素之一。微信小程序作為連接用戶與服務的重要橋梁&#xff0c;在提升用戶體驗方面發揮著重要作用。其中&#xff0c; openid&#xff08;開放身份標識符&#xff09;是微信小…

《Python星球日記》第25天:Pandas 數據分析

名人說&#xff1a;路漫漫其修遠兮&#xff0c;吾將上下而求索。—— 屈原《離騷》 創作者&#xff1a;Code_流蘇(CSDN)&#xff08;一個喜歡古詩詞和編程的Coder&#x1f60a;&#xff09; 訂閱專欄&#xff1a;《Python星球日記》 目錄 一、引言二、數據分組與聚合1. 分組操…