node.js学习笔记:中间件

Node.js中间件详解与实践

node.js学习笔记:中间件

      • 一、中间件的基本结构
      • 二、编写和使用中间件的步骤
        • 1. 编写中间件函数
        • 2. 注册中间件
        • 3. 错误处理中间件
      • 三、中间件的核心特性
      • 四、常见中间件类型
      • 总结

在 Node.js(尤其是 Express 框架)中,中间件(Middleware)是一个函数,它可以访问请求对象(req)、响应对象(res)以及应用程序的下一个中间件函数(next)。中间件的主要作用是:处理请求、修改请求/响应对象、终止请求-响应周期,或调用下一个中间件。

一、中间件的基本结构

一个标准的 Express 中间件函数包含 3 个参数:req(请求)、res(响应)、next(下一个中间件)。如果是错误处理中间件,则有 4 个参数:errreqresnext

基本格式:

// 普通中间件
const myMiddleware = (req, res, next) => {
  // 1. 处理逻辑(如日志、验证、修改req/res等)
  // 2. 调用 next() 交给下一个中间件;或用 res.send() 终止请求
  next(); // 必须调用,否则请求会被挂起
};

// 错误处理中间件(多一个 err 参数)
const errorMiddleware = (err, req, res, next) => {
  // 处理错误
  res.status(500).send('服务器错误:' + err.message);
};

二、编写和使用中间件的步骤

以 Express 为例,编写中间件并应用到项目中,通常分为 3 步:

1. 编写中间件函数

根据需求实现具体逻辑,例如:

示例 1:日志中间件(记录请求信息)

// 记录请求的方法、URL、时间
const loggerMiddleware = (req, res, next) => {
  const { method, url } = req;
  const time = new Date().toLocaleString();
  console.log(`[${time}] ${method} ${url}`);
  next(); // 交给下一个中间件
};

示例 2:参数验证中间件(检查请求参数)

// 验证 POST 请求的 body 中是否包含 username
const validateUserMiddleware = (req, res, next) => {
  if (!req.body.username) {
    // 参数错误,直接响应,终止请求
    return res.status(400).send('缺少 username 参数');
  }
  next(); // 参数正确,继续下一步
};

示例 3:异步中间件(处理异步操作)

// 模拟异步查询数据库,检查用户是否存在
const checkUserExists = async (req, res, next) => {
  try {
    const userId = req.params.id;
    // 模拟数据库查询
    const user = await db.findUser(userId); // 假设 db.findUser 是异步函数
    if (!user) {
      return res.status(404).send('用户不存在');
    }
    // 将查询结果挂载到 req 上,供后续中间件使用
    req.user = user;
    next();
  } catch (err) {
    // 异步错误需传递给错误处理中间件
    next(err); // 调用 next(err) 会触发错误处理中间件
  }
};
2. 注册中间件

通过 app.use() 或路由方法(如 app.get())注册中间件,使其生效。

全局中间件(对所有请求生效):

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

// 注册日志中间件(所有请求都会经过它)
app.use(loggerMiddleware);

// 解析 JSON 请求体的内置中间件(Express 自带)
app.use(express.json());

局部中间件(仅对特定路由生效):

// 仅对 POST /user 生效的验证中间件
app.post('/user', validateUserMiddleware, (req, res) => {
  res.send(`创建用户:${req.body.username}`);
});

// 对 /user/:id 路由生效的异步中间件
app.get('/user/:id', checkUserExists, (req, res) => {
  // 使用 checkUserExists 中间件挂载的 req.user
  res.send(`用户信息:${JSON.stringify(req.user)}`);
});

多个中间件串联

// 多个中间件按顺序执行
app.get(
  '/profile',
  authMiddleware, // 先验证登录
  checkRoleMiddleware, // 再检查权限
  (req, res) => { // 最后处理响应
    res.send('用户资料');
  }
);
3. 错误处理中间件

专门处理请求过程中产生的错误(同步/异步错误),必须定义 4 个参数(err, req, res, next),否则 Express 会将其视为普通中间件。

// 注册错误处理中间件(通常放在所有路由之后)
app.use((err, req, res, next) => {
  console.error('错误详情:', err.stack);
  // 区分错误类型,返回不同状态码
  if (err.type === 'validation') {
    return res.status(400).send(err.message);
  }
  // 未知错误返回 500
  res.status(500).send('服务器内部错误');
});

触发错误处理中间件

  • 同步错误:直接 throw new Error('错误信息')
  • 异步错误:调用 next(err)(如示例 3 中的 next(err)

三、中间件的核心特性

  1. 执行顺序:按注册顺序执行,先注册的中间件先处理请求(类似流水线)。

    app.use((req, res, next) => {
      console.log('中间件 1');
      next();
    });
    app.use((req, res, next) => {
      console.log('中间件 2');
      next();
    });
    // 访问任何接口,会先打印 "中间件 1",再打印 "中间件 2"
    
  2. 终止请求:如果中间件中调用了 res.send()res.json() 等响应方法,请求-响应周期会终止,后续中间件不再执行。

    app.use((req, res, next) => {
      res.send('终止请求');
      next(); // 这行代码不会生效,因为响应已发送
    });
    app.use((req, res, next) => {
      console.log('不会执行');
    });
    
  3. 修改请求/响应对象:中间件可以给 reqres 添加属性/方法,供后续中间件或路由使用(如示例 3 中的 req.user)。

四、常见中间件类型

  • 应用级中间件:通过 app.use() 注册,对所有路由生效。
  • 路由级中间件:通过 router.use() 注册,仅对特定路由模块生效。
  • 内置中间件:Express 自带的中间件,如 express.json()(解析 JSON 请求体)、express.static()(托管静态资源)。
  • 第三方中间件:如 cors(处理跨域)、morgan(日志)、helmet(安全头),需通过 npm 安装后使用。

总结

编写中间件的核心是:

  1. 定义一个接收 req, res, next(或 err, req, res, next)的函数。
  2. 在函数中实现特定逻辑(日志、验证、异步操作等)。
  3. 调用 next() 传递控制权,或用 res.send() 终止请求。
  4. 通过 app.use() 或路由方法注册中间件,注意执行顺序。

中间件是 Express 的核心思想,掌握它可以灵活处理各种请求场景,提高代码复用性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值