当前位置: 首页 > news >正文

Express中间件(Middleware)详解:从零开始掌握(1)

1. 中间件是什么?

想象中间件就像一个"加工流水线",请求(Request)从进入服务器到返回响应(Response)的过程中,会经过一个个"工作站"进行处理。

简单定义:中间件是能够访问请求对象(req)、响应对象(res)和下一个中间件函数(next)的函数。

2. 基本结构

一个最基本的中间件函数长这样:

function myMiddleware(req, res, next) {
  // 对req或res做一些处理
  console.log('这是中间件');
  next(); // 告诉Express转到下一个中间件
}

3. 中间件的工作原理

Express应用的请求处理流程就像这样:

请求 → 
中间件1 → 
中间件2 → 
... → 
路由处理器 → 
响应

每个中间件可以:

  • 执行任何代码
  • 修改请求和响应对象
  • 结束请求-响应循环
  • 调用下一个中间件

类型:

类型示例特点
应用级app.use()对所有请求生效
路由级router.use()仅对特定路由生效
错误处理app.use((err, req, res, next))必须4个参数
内置express.json()Express提供
第三方body-parser社区贡献

关键点

  • 每个中间件通过调用next()将控制权传递给下一个
  • 如果不调用next(),请求处理会终止
  • 错误处理中间件需要4个参数:(err, req, res, next)

4. 实际例子:记录请求日志

const express = require('express');
const app = express();

// 自定义日志中间件
app.use((req, res, next) => {
  console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
  next(); // 必须调用next()才能继续
});

app.get('/', (req, res) => {
  res.send('首页');
});

app.listen(3000);

看下日志:

5. 中间件类型

应用级中间件

// 对所有路由生效
app.use(myMiddleware);

// 对特定路由生效
app.use('/admin', adminMiddleware);

路由级中间件

router.use(middlewareFunction);

内置中间件

app.use(express.json()); // 解析JSON请求体
app.use(express.urlencoded({ extended: true })); // 解析表单数据
app.use(express.static('public')); // 静态文件服务

错误处理中间件

// 注意有4个参数
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('出错了!');
});

第三方中间件

const morgan = require('morgan');
app.use(morgan('dev')); // 日志中间件

6. 中间件执行顺序练习

app.use((req, res, next) => {
  console.log('第一');
  next();
});

app.use((req, res, next) => {
  console.log('第二');
  next();
});

app.get('/', (req, res) => {
  console.log('最后');
  res.send('完成');
});

7. 重要原则

  1. 顺序很重要:中间件按添加顺序执行
  2. 必须调用next():除非你想终止流程
  3. 错误处理中间件:必须放在最后
  4. 可以修改req/res:后面的中间件会看到修改

8. 练习

        8.1. 记录请求耗时的中间件

const express = require('express');
const app = express();

// 记录请求耗时的中间件
app.use((req, res, next) => {
  const startTime = Date.now(); // 记录开始时间
  
  // 在响应结束时计算耗时
  res.on('finish', () => {
    const duration = Date.now() - startTime;
    console.log(`${req.method} ${req.url} - ${duration}ms`);
  });
  
  next(); // 继续处理请求
});

// 测试路由
app.get('/', (req, res) => {
  // 模拟耗时操作
  setTimeout(() => {
    res.send('首页');
  }, 300);
});

app.listen(3000, () => {
  console.log('服务器运行在 http://localhost:3000');
});

          8.2. 记录请求耗时的中间件

//  验证API密钥的中间件
const express = require('express');
const app = express();

// API密钥验证中间件
const apiKeyValidator = (req, res, next) => {
  const validApiKeys = ['123-abc', '456-def', '789-ghi'];
  const apiKey = req.headers['x-api-key'] || req.query.apiKey;
  
  if (!apiKey) {
    return res.status(401).json({ error: '缺少API密钥' });
  }
  
  if (!validApiKeys.includes(apiKey)) {
    return res.status(403).json({ error: '无效的API密钥' });
  }
  
  console.log(`API密钥验证通过: ${apiKey}`);
  next(); // 验证通过
};

// 受保护的路由
app.get('/protected', apiKeyValidator, (req, res) => {
  res.json({ message: '你已访问受保护的内容' });
});

// 测试方式:
// 1. curl http://localhost:3000/protected?apiKey=123-abc
// 2. curl -H "x-api-key: 123-abc" http://localhost:3000/protected

app.listen(3000);

        8.3. 组合多个中间件

const express = require('express');
const app = express();

// 中间件1: 记录请求信息
const requestLogger = (req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.ip} ${req.method} ${req.path}`);
  next();
};

// 中间件2: 验证用户身份
const userAuth = (req, res, next) => {
  // 模拟用户验证
  const isAuthenticated = Math.random() > 0.3; // 70%概率通过
  
  if (isAuthenticated) {
    req.user = { id: 123, name: '示例用户' }; // 附加用户信息到请求对象
    next();
  } else {
    res.status(401).send('请先登录');
  }
};

// 中间件3: 检查管理员权限
const adminCheck = (req, res, next) => {
  if (req.user && req.user.isAdmin) {
    next();
  } else {
    res.status(403).send('需要管理员权限');
  }
};

// 组合使用多个中间件
app.get('/profile', 
  requestLogger, 
  userAuth, 
  (req, res) => {
    res.send(`欢迎, ${req.user.name}`);
  }
);

app.get('/admin', 
  requestLogger, 
  userAuth, 
  adminCheck, 
  (req, res) => {
    res.send('管理员面板');
  }
);

// 测试路由
app.get('/public', requestLogger, (req, res) => {
  res.send('公开内容');
});

app.listen(3000);

本节到这里就结束了,下节将讲解进阶版中间件。

Express中间件(Middleware)详解:从零开始掌握(2)-CSDN博客

相关文章:

  • 在Java项目中,引入【全局异常处理器】
  • HarmonyOS-ArkUI V2装饰器-@Once
  • 第一节:React 基础篇-React虚拟DOM原理及Diff算法优化策略
  • 【Web功能测试】注册与登录功能测试用例设计深度解析
  • (十四)安卓开发中的RecyclerView详解
  • Python 和 JavaScript两种语言的相似部分-由DeepSeek产生
  • 计算机操作系统-【死锁】
  • 信奥赛之c++基础(循环结构之for循环)
  • Java常用工具算法-6--秘钥托管云服务3--微软zure Key Vault
  • 第5章,将 Toy IR 程序部分地下降到更低层的 dialect 以便优化
  • 【Grok 大模型深度解析】第二期:架构探秘与训练哲学
  • 在AMGX中使用MPI加载自定义分布式矩阵和向量
  • 自定义函数:为接口开发增添灵活性 - Apipost 的独特优势
  • [特殊字符] 各领域 Dummy 开关实现方式大集合
  • SQL:单表查询基础
  • 面试之《前端信息加密》
  • 使用 Python 扫描 Windows 下的 Wi-Fi 网络实例演示
  • 【Qt】qDebug() << “中文测试“; 乱码问题
  • 论文阅读:2024-arxiv How to Steer LLM Latents for Hallucination Detection?
  • 多坐标系变换全解析:从相机到WGS-84的空间坐标系详解
  • 江门公司网站建设/学做网站培训班要多少钱
  • 响应式网站 图片尺寸奇数/百度最新版本2022
  • 游学做的好的网站/网络推广平台哪家公司最好
  • 永久免费云服务器推荐/北京seo关键词排名优化软件
  • 免费的网站域名申请/中关村在线app
  • 四川建设工程网上合同备案网站/如何推广普通话的建议6条