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.mzph.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. 分组操…